diff -Nru a/Documentation/SubmittingPatches b/Documentation/SubmittingPatches --- a/Documentation/SubmittingPatches Thu Jan 22 18:59:23 2004 +++ b/Documentation/SubmittingPatches Thu Jan 22 18:59:23 2004 @@ -241,7 +241,7 @@ Simple example, of poor code: - dev = init_etherdev (NULL, 0); + dev = alloc_etherdev (sizeof(struct funky_private)); if (!dev) return -ENODEV; #ifdef CONFIG_NET_FUNKINESS @@ -256,7 +256,7 @@ #endif (in the code itself) - dev = init_etherdev (NULL, 0); + dev = alloc_etherdev (sizeof(struct funky_private)); if (!dev) return -ENODEV; init_funky_net(dev); diff -Nru a/Documentation/networking/8139too.txt b/Documentation/networking/8139too.txt --- a/Documentation/networking/8139too.txt Thu Jan 22 18:59:25 2004 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,449 +0,0 @@ - - "8139too" Fast Ethernet driver for Linux - RTL-8139, -8129, and -8130 10/100 Fast Ethernet adapters - - Copyright 2000,2001 Jeff Garzik - - http://sourceforge.net/projects/gkernel/ - - - Architectures supported (all PCI platforms): - x86, Alpha AXP, PowerPC, Sparc64 - - Kernel versions supported: 2.4.x - - - -Disclaimer ----------- - -DO NOT CONTACT DONALD BECKER FOR SUPPORT OF THIS DRIVER, his driver is -completely different and maintained independently of the 8139too code base. - - - -Requirements ------------- -Kernel 2.4.3 or later. -A Fast Ethernet adapter containing an RTL8139-based chip. - - - -Introduction ------------- - -The "8139too" Fast Ethernet driver for Linux 2.4.0 is a substantial -modification of the experimental rtl8139 driver from Donald Becker, -some versions of which appeared in 2.2.x and 2.3.x kernels. The -RTL-8139 is a very low-cost Fast Ethernet chip, which makes it very -popular. - -The step from 2.2.x to 2.4.x kernels brings many new features to Linux -device drivers. Features for MMIO resources, a standard hot-plug API, -and other interfaces are now becoming requirements, as drivers move -off the x86 platform. With that in mind, I have begun updating the -RTL-8139 driver to current 2.3.x (2.4) kernel standards and APIs, and -fixing the problems that users have been encountering. - - - -Features of 8139too -------------------- -[note - this list intended for people familiar with kernel drivers] - -** 100% MMIO, for full speed operation. All users (so far) have -reported performance increases over their existing RTL drivers. - -** Multi-platform support: x86, Alpha, PPC, ... - -** Use proper SMP spinlocking, fixing SMP interrupt bugs, making the -driver portable to non-x86 SMP platforms in the process. - -** Use new PCI driver API for seamless, low-maintenance hot-plug support - -** Several bugs fixes from original rtl8139 1.08r (October 5, 1999), -including the very common "transmit timeout" problem. - -* Use new resource allocation API, required for hot-plug support -* Use new register read/write macros -* initcall support (module_init/exit) -* vastly improved debug tracing support -* code formatting in many places for readability -* use new init_etherdev() facilities - -...and probably some other less important changes which I forgot. - - - -Installation ------------- - -OPTION 1: Build inside kernel tree (into kernel image, or as module) - - (overwrite 8139too driver in kernel tree with different version) - 1) cp 8139too.c $my_source_tree/drivers/net/8139too.c - -OPTION 2: Build outside kernel tree - - Use the included Makefile. - - - -Tested Adapters ---------------- -AOpen ALN-325C -AT-2500TX 10/100 PCI Fast Ethernet Network Adapter Card -D-Link DFE-530TX -Cnet CNF401 'SinglePoint' 10/100 Base-TX -Genius GF 100TXR4 Fast Ethernet 10/100M PCI Network Card -KTI KF-230TX -KTI KF-230TX/2 -Lantech FastNet TX -Ovislink Fast Ethernet -Planet ENW-9504 (V.4) 10/100 -SDT Jeoun Fast PCI-TX -SMC EZNET 10/100 -UNEX NexNIC ND012C - -(please add your adapter model to this list) - - - -Status of Platform Support --------------------------- - -(see errata below for details) - -x86: tested, stable -Alpha AXP: tested, stable -PowerPC: tested, unstable -Sparc64: not tested - - - -Special Thanks --------------- -The following people contributed invaluable testing time, feedback -and/or patches during the development of this driver. Thanks to all -of them. - -Donald Becker, Alan Cox, Richard Stallman, Linus Torvalds - inspiration - -Alan Cox, Gerard Roudier - insight on posted MMIO writes - -Martin Mares - code review - -Tigran Aivazian - testing, code review, and a bug fix - -Chmouel Boudjnah, Alexander Dietrich, Oleg Drokin, -James Fidell, Taso Hatzi, Peter K - intrepid test team - -And thanks to every supporter free software. - -(see top of 8139too.c for further credits and kudos) - - - -Submitting Bug Reports ----------------------- -Obtain and compile the modified rtl8139-diag source code from the -8139too driver Web site, http://sourceforge.net/projects/gkernel/ -This diagnostics programs, originally from Donald Becker, has been -modified to display all registers on your RTL8139 chip, not just the -first 0x80. - -If possible, send the output of a working and broken driver with - rtl8139-diag -mmaaavvveefN > my-output-file.txt - -Send "lspci -vvv" or "cat /proc/pci" output for PCI information. - - - -Known Bugs / Errata / To-Do ---------------------------- -The following issues are known, and are actively being pursued. Patches -to resolve these issues is welcome. If a problem occurs which is not in -the list, please report it. That's why we do beta releases, after all... - - - -1) Work with Donald to merge fixes and updates into his driver. - -2) ETHTOOL_SSET support - -3) PPC platform has stability problems. (XXX: verify this is still true) - -4) Sparc64 platform not tested at all. - -8) Much improved command line / module parameter setup. (patches and -suggestions welcome) (WIP) - -9) Better documentation. (patches welcome) - -12) 10base-T support flaky or slow (todo: verify this is still true) - - - - -Change History --------------- - -Version 0.9.26 - August 9, 2002 - -* Fix MII ioctl phy id corruption. -* Fix big-endian multicast bug. -* Support register dumps via ethtool. -* Fix several uses of 'len' after potential skb free, in dev->hard_start_xmit -* Replace several "magic numbers" with their proper representation - constants in linux/mii.h. -* Support ethtool media interface via generic kernel MII API -* Export NIC-specific statistics via ethtool. -* Proper support for RTL8139 rev K. (can be disabled via - compile-time conditional) -* Add PCI ids for new 8139 boards. -* Use ethernet crc via generic linux/crc32.h kernel API. -* Better RX reset. Old rx-reset method still available via - a compile-time conditional. -* Only account specific RX errors if rx_status is !OK - - -Version 0.9.22 - November 8, 2001 - -* Additional retries before aborting Tx -* Do not write other TxConfig bits when writing clear-abort bit. -* Ack TxErr intr status after each Tx abort, too. -* Fix oops in interface restart - - -Version 0.9.21 - November 1, 2001 - -* Disable early Rx, it hurts performance and creates races. -* Remove DPRINTK macro function tracing. -* Better interrupt sharing behavior. -* Acknowledge PCI errors. -* Remove early-Rx acknowledgement, unnecessary -* Remove code for uncommon case where Tx packets are - properly aligned, and do not need to be copied. - Tx packets are now always copied into a static DMA buffer, - which is allocated at interface open. -* Fix problems with kernel thread exit. - - -Version 0.9.20 - October 18, 2001 - -* Print out notice when 8139C+ chip is detected -* Add id for D-Link DFE690TXD pcmcia cardbus card (Gert Dewit) - - -Version 0.9.19 - October 9, 2001 - -* Eliminate buffer copy for unaligned Tx's (manfred) -* Better RX error recovery (manfred) -* Wake-On-LAN and ETHTOOL_GSET support (Kalle Niemitalo) -* Fix assertion in PIO mode (various) - - -Version 0.9.18 - July 6, 2001 - -* Fix race leading to crashes on some machines. -* Minimize race leading to low performance. -* Correct interrupt acknowledgement to cover all three - relevant Rx events. -* Add ethtool driver info support. -* Collect additional driver-internal statistics. -* Add descriptions for module parameters. -* Support new SIOCxMIIxxx ioctls added in kernel 2.4.6. -* Multicast filter big endian fix. -* Support new PCI PM API added in kernel 2.4.6. - - -Version 0.9.17 - May 7, 2001 - -* Fix chipset wakeup bug which prevent media connection for 8139B -* Print out "media is unconnected..." instead of - "partner ability 0000" - - -Version 0.9.16 - April 14, 2001 - -* Complete MMIO audit, disable read-after-every-write -* Update Rx interrupt handling -* Enable Early Rx thresholds, highly recommended to reduce - Rx FIFO overflow -* Make 8129 support conditional -* Support for new 2.4.3 kernel APIs -* More correct PIO/MMIO PCI BAR region size checking -* Add check for totally dead/missing hardware -* Disable media timer code to "set full duplex" -* s/spin_lock_irq/spin_lock_irqsave/ -* Only set AcceptMulticast if more than one mc address -* Only set rx_mode if changed, in set_rx_mode -* Only suspend/resume if interface is up -* Always print out version upon module load, even if no devices found - - -Version 0.9.15 - February 20, 2001 - -* Call pci_enable_device to wake up/assign resource to device, - before actually using it. -* Support wacky clone PCI ids (report from Norival Toniato Junior) -* Text spelling corrections -* Make sure tp->phys[] is signed -* Always wake queue after hw restart, in tx_timeout -* Record time of last received packet - - -Version 0.9.14 - January 11, 2001 - -* Merge some changes from Becker version 1.13: - * Add DFE 538TX PCI id - * MII read/write functions updated - * Cfg93[45]6 lock/unlock fix - * RTL-8129 (MII) support -* Clean up spinlocking - - -Version 0.9.13 - December, 2000 - -* Clear blocked signals, avoid buffer overrun setting current->comm -* Remove bogus PCI BAR length assertions -* Remove unused 'debug' module parameter - - -Version 0.9.12 - November 23, 2000 - -* Kill major Tx stop/wake queue race -* Use SET_MODULE_OWNER and fix module unload race -* Fix cable length ("Twister") tuning -* Proper media[] array length checking -* Replace timer with kernel thread for twister tuning state machine - and media checking. Fixes mdio_xxx locking, now mdio_xxx is always - protected by rtnl_lock semaphore. -* Correct some sledgehammer a.k.a. overzealous spin-locks -* Performance: Eliminate atomic_t for Tx counters, we don't need it -* Performance: Don't copy Tx buffer if the rare case occurs where it - is aligned perfectly for us. -* Eliminate needless casting of dev->priv -* PIO mode selection and Twister tuning are now CONFIG_xxx options - (though purposefully not in net/Config.in... yet) - - -Version 0.9.11 - October 28, 2000 - -* Do not fail when PIO and MMIO region lengths do not match. - (They don't on some CardBus models, at least) -* Sanity check Rx packet status and size (Tobias) -* When handling a Tx timeout, disable Tx ASAP if not already. -* Do not inline Tx interrupt handler (better register usage) -* Handle dirty_tx signed integer wrap -* Do not abort Rx processing on lack of memory, keep going - until the current Rx ring is completely handling. (Tobias) -* Clean up rtl8139_close -* Whitespace correction for dev_kfree_skb_irq call - - -Version 0.9.10 - September 12, 2000 - -* Never wrap an Rx packet (faster Rx interrupt handling) -* Clear all TxAborted conditions (bug fix) -* Correct copyright -* More credits -* Update NWay doc URL -* Clean up commonly used ifdef switches -* Reorg info displayed at bootup/modprobe time -* Remove some unneeded spinlocks -* Misc cosmetic code cleanup -* Always print interrupt status for abnormal interrupts -* Use RealTek-recommended FIFO and DMA burst settings (1024 bytes) - - -Version 0.9.9 - September 9, 2000 - -* Fix oops-able bug in Rx ring wrap calculation (David Ford) -* Use PIO instead of MMIO when USE_IO_OPS is defined -* Move Rx error handling out of Rx interrupt handler, resulting in - tighter Rx interrupt processing - - -Version 0.9.8 - September 7, 2000 - -* Propagate request_irq error value (andrew morton) -* Correct potential oops bug in PCI DMA unmap code -* Fix bugs related to counting/discounting of 32-bit CRC in each Rx packet -* Fix 16/32-bit bug in interrupt status check -* Timer cleanups (andrew morton) - - -Version 0.9.7 - June 11, 2000 - -* Fix support for older chips (RTL8139 early chips should now work again) - - -Version 0.9.6 - May 30, 2000 - -* Fix 4-extra-bytes bug - (thanks to Markus Westergren, via Santiago Garcia Mantinan) -* Yet more improved chip recognition - - -Version 0.9.5 - May 17, 2000 - -* Improved chip version recognition -* Continue banging away at receiver hang problem -* Use spin_lock_irq in another spot -* Don't print anything on pci_enable_device, it does so for us -* Disable buggy NWay code -* Define TxConfig bitmasks - - -Version 0.9.4.1 - April 27, 2000 - third public beta release - -* Replace several "magic numbers" with symbolic constants -* Differentiate between board-specific info and chip-specific info - (allows for easier support of specific boards or chips) -* Move some of the transmit side outside of the spinlock - by using atomic variables. Use spin_lock_irq instead of - spin_lock_irq{save,restore} in select places, for better performance. -* New module option "media" for forcing media selection. Functions the - same as "options" in other drivers, and will soon be renamed - 'options' to be homogeneous. -* New power management wake-up code -* Slightly more verbose chip id messages in kernel log -* Add/correct chip register constant list -* New chipset wake up (open) logic -* No longer locks CONFIGx updates -* Do not set Interfame Gap (IFG) bits in TxConfig -* Better Rx reset logic in case of Rx FIFO Overflow -* For chips which support it, enable bit to automatically clear Rx - FIFO overflow -* No longer enable and disable interrupts in interrupt handler - (technique borrowed from BSD driver, appears to have problems - with some chips) -* H/W spinlock now protects ioctl -* Chipset-dependent RxConfig settings - - -Version 0.9.3.3.2 - Feb 22, 2000 - second public beta release - -* Begin integration of Daniel Kobras' MMIO flush patch (disabled for now) -* Softnet logic updates to fix bugs and improve performance -* Dynamic sizing of I/O resources (0x80 for older chips, 0xFF for newer ones) -* Remove bogus SiS entries from PCI probe table -* Add support for cards - "Delta Electronics 8139 10/100BaseTX" - "Addtron Technolgy 8139 10/100BaseTX" -* Fix major bug with rx ring buffer size (also present in rtl8139.c 1.08r) -* PCI DMA mapping by Dave Miller -* Complete rewrite of SMP locking logic -* Hotplug support -* Call rtl8139_hw_start from rtl8139_open, and remove duplicated code - from rtl8139_open -* Reset NWay registers to sane defaults on rtl8139_open/hw_start -* Miscellaneous code cleanup - - -Version 0.7.0 - Feb 7, 2000 - first public beta release -* Initial public version, derived from Donald Becker's rtl8139.c v1.08r - -[EOF] - diff -Nru a/Documentation/networking/bonding.txt b/Documentation/networking/bonding.txt --- a/Documentation/networking/bonding.txt Thu Jan 22 18:59:24 2004 +++ b/Documentation/networking/bonding.txt Thu Jan 22 18:59:24 2004 @@ -21,7 +21,7 @@ Table of Contents ================= - + Installation Bond Configuration Module Parameters @@ -66,7 +66,7 @@ /usr/include/linux. To install ifenslave.c, do: - # gcc -Wall -Wstrict-prototypes -O -I/usr/src/linux/include ifenslave.c -o ifenslave + # gcc -Wall -Wstrict-prototypes -O -I/usr/src/linux/include ifenslave.c -o ifenslave # cp ifenslave /sbin/ifenslave @@ -74,10 +74,10 @@ ================== You will need to add at least the following line to /etc/modules.conf -so the bonding driver will automatically load when the bond0 interface is -configured. Refer to the modules.conf manual page for specific modules.conf -syntax details. The Module Parameters section of this document describes each -bonding driver parameter. +so the bonding driver will automatically load when the bond0 interface is +configured. Refer to the modules.conf manual page for specific modules.conf +syntax details. The Module Parameters section of this document describes each +bonding driver parameter. alias bond0 bonding @@ -113,7 +113,7 @@ network interface be a slave of bond1. Restart the networking subsystem or just bring up the bonding device if your -administration tools allow it. Otherwise, reboot. On Red Hat distros you can +administration tools allow it. Otherwise, reboot. On Red Hat distros you can issue `ifup bond0' or `/etc/rc.d/init.d/network restart'. If the administration tools of your distribution do not support @@ -128,30 +128,30 @@ (use appropriate values for your network above) -You can then create a script containing these commands and place it in the +You can then create a script containing these commands and place it in the appropriate rc directory. If you specifically need all network drivers loaded before the bonding driver, -adding the following line to modules.conf will cause the network driver for +adding the following line to modules.conf will cause the network driver for eth0 and eth1 to be loaded before the bonding driver. probeall bond0 eth0 eth1 bonding -Be careful not to reference bond0 itself at the end of the line, or modprobe +Be careful not to reference bond0 itself at the end of the line, or modprobe will die in an endless recursive loop. -To have device characteristics (such as MTU size) propagate to slave devices, -set the bond characteristics before enslaving the device. The characteristics +To have device characteristics (such as MTU size) propagate to slave devices, +set the bond characteristics before enslaving the device. The characteristics are propagated during the enslave process. -If running SNMP agents, the bonding driver should be loaded before any network -drivers participating in a bond. This requirement is due to the the interface -index (ipAdEntIfIndex) being associated to the first interface found with a -given IP address. That is, there is only one ipAdEntIfIndex for each IP -address. For example, if eth0 and eth1 are slaves of bond0 and the driver for -eth0 is loaded before the bonding driver, the interface for the IP address -will be associated with the eth0 interface. This configuration is shown below, -the IP address 192.168.1.1 has an interface index of 2 which indexes to eth0 +If running SNMP agents, the bonding driver should be loaded before any network +drivers participating in a bond. This requirement is due to the the interface +index (ipAdEntIfIndex) being associated to the first interface found with a +given IP address. That is, there is only one ipAdEntIfIndex for each IP +address. For example, if eth0 and eth1 are slaves of bond0 and the driver for +eth0 is loaded before the bonding driver, the interface for the IP address +will be associated with the eth0 interface. This configuration is shown below, +the IP address 192.168.1.1 has an interface index of 2 which indexes to eth0 in the ifDescr table (ifDescr.2). interfaces.ifTable.ifEntry.ifDescr.1 = lo @@ -189,10 +189,10 @@ Module Parameters ================= -Optional parameters for the bonding driver can be supplied as command line -arguments to the insmod command. Typically, these parameters are specified in -the file /etc/modules.conf (see the manual page for modules.conf). The -available bonding driver parameters are listed below. If a parameter is not +Optional parameters for the bonding driver can be supplied as command line +arguments to the insmod command. Typically, these parameters are specified in +the file /etc/modules.conf (see the manual page for modules.conf). The +available bonding driver parameters are listed below. If a parameter is not specified the default value is used. When initially configuring a bond, it is recommended "tail -f /var/log/messages" be run in a separate window to watch for bonding driver error messages. @@ -202,19 +202,19 @@ during link failures. arp_interval - - Specifies the ARP monitoring frequency in milli-seconds. - If ARP monitoring is used in a load-balancing mode (mode 0 or 2), the - switch should be configured in a mode that evenly distributes packets - across all links - such as round-robin. If the switch is configured to - distribute the packets in an XOR fashion, all replies from the ARP - targets will be received on the same link which could cause the other + + Specifies the ARP monitoring frequency in milli-seconds. + If ARP monitoring is used in a load-balancing mode (mode 0 or 2), the + switch should be configured in a mode that evenly distributes packets + across all links - such as round-robin. If the switch is configured to + distribute the packets in an XOR fashion, all replies from the ARP + targets will be received on the same link which could cause the other team members to fail. ARP monitoring should not be used in conjunction - with miimon. A value of 0 disables ARP monitoring. The default value + with miimon. A value of 0 disables ARP monitoring. The default value is 0. - + arp_ip_target - + Specifies the ip addresses to use when arp_interval is > 0. These are the targets of the ARP request sent to determine the health of the link to the targets. Specify these values in ddd.ddd.ddd.ddd @@ -223,8 +223,8 @@ maximum number of targets that can be specified is set at 16. downdelay - - Specifies the delay time in milli-seconds to disable a link after a + + Specifies the delay time in milli-seconds to disable a link after a link failure has been detected. This should be a multiple of miimon value, otherwise the value will be rounded. The default value is 0. @@ -247,7 +247,7 @@ and bond2 will be created. The default value is 1. miimon - + Specifies the frequency in milli-seconds that MII link monitoring will occur. A value of zero disables MII link monitoring. A value of 100 is a good starting point. See High Availability section for @@ -258,7 +258,7 @@ Specifies one of the bonding policies. The default is round-robin (balance-rr). Possible values are (you can use either the text or numeric option): - + balance-rr or 0 Round-robin policy: Transmit in a sequential order @@ -273,7 +273,7 @@ externally visible on only one port (network adapter) to avoid confusing the switch. This mode provides fault tolerance. - + balance-xor or 2 XOR policy: Transmit based on [(source MAC address @@ -293,7 +293,7 @@ groups that share the same speed and duplex settings. Transmits and receives on all slaves in the active aggregator. - + Pre-requisites: 1. Ethtool support in the base drivers for retrieving the @@ -317,7 +317,7 @@ Ethtool support in the base drivers for retrieving the speed of each slave. - balance-alb or 6 + balance-alb or 6 Adaptive load balancing: includes balance-tlb + receive load balancing (rlb) for IPV4 traffic and does not require @@ -327,7 +327,7 @@ overwrites the src hw address with the unique hw address of one of the slaves in the bond such that different clients use different hw addresses for the server. - + Receive traffic from connections created by the server is also balanced. When the server sends an ARP Request the bonding driver copies and saves the client's IP information @@ -363,25 +363,11 @@ 2. Base driver support for setting the hw address of a device also when it is open. This is required so that there will always be one slave in the team using the bond hw - address (the current_slave) while having a unique hw - address for each slave in the bond. If the current_slave - fails it's hw address is swapped with the new current_slave + address (the curr_active_slave) while having a unique hw + address for each slave in the bond. If the curr_active_slave + fails it's hw address is swapped with the new curr_active_slave that was chosen. -multicast - - Option specifying the mode of operation for multicast support. - Possible values are: - - disabled or 0 - Disabled (no multicast support) - - active or 1 - Enabled on active slave only, useful in active-backup mode - - all or 2 - Enabled on all slaves, this is the default - primary A string (eth0, eth2, etc) to equate to a primary device. If this @@ -397,11 +383,11 @@ primary is only valid in active-backup mode. updelay - - Specifies the delay time in milli-seconds to enable a link after a + + Specifies the delay time in milli-seconds to enable a link after a link up status has been detected. This should be a multiple of miimon value, otherwise the value will be rounded. The default value is 0. - + use_carrier Specifies whether or not miimon should use MII or ETHTOOL @@ -529,20 +515,20 @@ ---------------------------- The bonding driver information files reside in the /proc/net/bonding directory. -Sample contents of /proc/net/bonding/bond0 after the driver is loaded with +Sample contents of /proc/net/bonding/bond0 after the driver is loaded with parameters of mode=0 and miimon=1000 is shown below. - + Bonding Mode: load balancing (round-robin) Currently Active Slave: eth0 MII Status: up MII Polling Interval (ms): 1000 Up Delay (ms): 0 Down Delay (ms): 0 - + Slave Interface: eth1 MII Status: up Link Failure Count: 1 - + Slave Interface: eth0 MII Status: up Link Failure Count: 1 @@ -550,34 +536,34 @@ 2) Network verification ----------------------- The network configuration can be verified using the ifconfig command. In -the example below, the bond0 interface is the master (MASTER) while eth0 and -eth1 are slaves (SLAVE). Notice all slaves of bond0 have the same MAC address +the example below, the bond0 interface is the master (MASTER) while eth0 and +eth1 are slaves (SLAVE). Notice all slaves of bond0 have the same MAC address (HWaddr) as bond0 for all modes except TLB and ALB that require a unique MAC address for each slave. [root]# /sbin/ifconfig -bond0 Link encap:Ethernet HWaddr 00:C0:F0:1F:37:B4 +bond0 Link encap:Ethernet HWaddr 00:C0:F0:1F:37:B4 inet addr:XXX.XXX.XXX.YYY Bcast:XXX.XXX.XXX.255 Mask:255.255.252.0 UP BROADCAST RUNNING MASTER MULTICAST MTU:1500 Metric:1 RX packets:7224794 errors:0 dropped:0 overruns:0 frame:0 TX packets:3286647 errors:1 dropped:0 overruns:1 carrier:0 - collisions:0 txqueuelen:0 + collisions:0 txqueuelen:0 -eth0 Link encap:Ethernet HWaddr 00:C0:F0:1F:37:B4 +eth0 Link encap:Ethernet HWaddr 00:C0:F0:1F:37:B4 inet addr:XXX.XXX.XXX.YYY Bcast:XXX.XXX.XXX.255 Mask:255.255.252.0 UP BROADCAST RUNNING SLAVE MULTICAST MTU:1500 Metric:1 RX packets:3573025 errors:0 dropped:0 overruns:0 frame:0 TX packets:1643167 errors:1 dropped:0 overruns:1 carrier:0 - collisions:0 txqueuelen:100 - Interrupt:10 Base address:0x1080 + collisions:0 txqueuelen:100 + Interrupt:10 Base address:0x1080 -eth1 Link encap:Ethernet HWaddr 00:C0:F0:1F:37:B4 +eth1 Link encap:Ethernet HWaddr 00:C0:F0:1F:37:B4 inet addr:XXX.XXX.XXX.YYY Bcast:XXX.XXX.XXX.255 Mask:255.255.252.0 UP BROADCAST RUNNING SLAVE MULTICAST MTU:1500 Metric:1 RX packets:3651769 errors:0 dropped:0 overruns:0 frame:0 TX packets:1643480 errors:0 dropped:0 overruns:0 carrier:0 - collisions:0 txqueuelen:100 - Interrupt:9 Base address:0x1400 + collisions:0 txqueuelen:100 + Interrupt:9 Base address:0x1400 Frequently Asked Questions @@ -605,9 +591,9 @@ 5. What happens when a slave link dies? - If your ethernet cards support MII or ETHTOOL link status monitoring - and the MII monitoring has been enabled in the driver (see description - of module parameters), there will be no adverse consequences. This + If your ethernet cards support MII or ETHTOOL link status monitoring + and the MII monitoring has been enabled in the driver (see description + of module parameters), there will be no adverse consequences. This release of the bonding driver knows how to get the MII information and enables or disables its slaves according to their link status. See section on High Availability for additional information. @@ -622,8 +608,8 @@ slave. If neither mii_monitor and arp_interval is configured, the bonding - driver will not handle this situation very well. The driver will - continue to send packets but some packets will be lost. Retransmits + driver will not handle this situation very well. The driver will + continue to send packets but some packets will be lost. Retransmits will cause serious degradation of performance (in the case when one of two slave links fails, 50% packets will be lost, which is a serious problem for both TCP and UDP). @@ -636,9 +622,9 @@ 7. Which switches/systems does it work with? - In round-robin and XOR mode, it works with systems that support + In round-robin and XOR mode, it works with systems that support trunking: - + * Many Cisco switches and routers (look for EtherChannel support). * SunTrunking software. * Alteon AceDirector switches / WebOS (use Trunks). @@ -646,7 +632,7 @@ models (450) can define trunks between ports on different physical units. * Linux bonding, of course ! - + In 802.3ad mode, it works with with systems that support IEEE 802.3ad Dynamic Link Aggregation: @@ -667,21 +653,21 @@ is then passed to all following slaves and remains persistent (even if the the first slave is removed) until the bonding device is brought down or reconfigured. - + If you wish to change the MAC address, you can set it with ifconfig: # ifconfig bond0 hw ether 00:11:22:33:44:55 The MAC address can be also changed by bringing down/up the device and then changing its slaves (or their order): - + # ifconfig bond0 down ; modprobe -r bonding # ifconfig bond0 .... up # ifenslave bond0 eth... This method will automatically take the address from the next slave that will be added. - + To restore your slaves' MAC addresses, you need to detach them from the bond (`ifenslave -d bond0 eth0'), set them down (`ifconfig eth0 down'), unload the drivers (`rmmod 3c59x', for @@ -729,27 +715,27 @@ ================= To implement high availability using the bonding driver, the driver needs to be -compiled as a module, because currently it is the only way to pass parameters +compiled as a module, because currently it is the only way to pass parameters to the driver. This may change in the future. -High availability is achieved by using MII or ETHTOOL status reporting. You -need to verify that all your interfaces support MII or ETHTOOL link status -reporting. On Linux kernel 2.2.17, all the 100 Mbps capable drivers and -yellowfin gigabit driver support MII. To determine if ETHTOOL link reporting -is available for interface eth0, type "ethtool eth0" and the "Link detected:" -line should contain the correct link status. If your system has an interface -that does not support MII or ETHTOOL status reporting, a failure of its link -will not be detected! A message indicating MII and ETHTOOL is not supported by -a network driver is logged when the bonding driver is loaded with a non-zero +High availability is achieved by using MII or ETHTOOL status reporting. You +need to verify that all your interfaces support MII or ETHTOOL link status +reporting. On Linux kernel 2.2.17, all the 100 Mbps capable drivers and +yellowfin gigabit driver support MII. To determine if ETHTOOL link reporting +is available for interface eth0, type "ethtool eth0" and the "Link detected:" +line should contain the correct link status. If your system has an interface +that does not support MII or ETHTOOL status reporting, a failure of its link +will not be detected! A message indicating MII and ETHTOOL is not supported by +a network driver is logged when the bonding driver is loaded with a non-zero miimon value. The bonding driver can regularly check all its slaves links using the ETHTOOL -IOCTL (ETHTOOL_GLINK command) or by checking the MII status registers. The -check interval is specified by the module argument "miimon" (MII monitoring). -It takes an integer that represents the checking time in milliseconds. It -should not come to close to (1000/HZ) (10 milli-seconds on i386) because it -may then reduce the system interactivity. A value of 100 seems to be a good -starting point. It means that a dead link will be detected at most 100 +IOCTL (ETHTOOL_GLINK command) or by checking the MII status registers. The +check interval is specified by the module argument "miimon" (MII monitoring). +It takes an integer that represents the checking time in milliseconds. It +should not come to close to (1000/HZ) (10 milli-seconds on i386) because it +may then reduce the system interactivity. A value of 100 seems to be a good +starting point. It means that a dead link will be detected at most 100 milli-seconds after it goes down. Example: @@ -761,7 +747,7 @@ alias bond0 bonding options bond0 miimon=100 -There are currently two policies for high availability. They are dependent on +There are currently two policies for high availability. They are dependent on whether: a) hosts are connected to a single host or switch that support trunking @@ -811,7 +797,7 @@ # ifenslave bond0 eth0 eth1 -2) High Availability on two or more switches (or a single switch without +2) High Availability on two or more switches (or a single switch without trunking support) --------------------------------------------------------------------------- This mode is more problematic because it relies on the fact that there @@ -870,10 +856,10 @@ connected to one switch and host2's to the other. Such system will survive a failure of a single host, cable, or switch. The worst thing that may happen in the case of a switch failure is that half of the hosts will be temporarily -unreachable until the other switch expires its tables. +unreachable until the other switch expires its tables. Example 2: Using multiple ethernet cards connected to a switch to configure - NIC failover (switch is not required to support trunking). + NIC failover (switch is not required to support trunking). +----------+ +----------+ @@ -957,7 +943,7 @@ servers, but may be useful when the front switches send multicast information on their links (e.g. VRRP), or even health-check the servers. Use the arp_interval/arp_ip_target parameters to count incoming/outgoing - frames. + frames. @@ -973,13 +959,12 @@ You will also find a lot of information regarding Ethernet, NWay, MII, etc. at www.scyld.com. -For new versions of the driver, patches for older kernels and the updated -userspace tools, take a look at Willy Tarreau's site : +Patches for 2.2 kernels are at Willy Tarreau's site : - http://wtarreau.free.fr/pub/bonding/ - - http://www-miaif.lip6.fr/willy/pub/bonding/ + - http://www-miaif.lip6.fr/~tarreau/pub/bonding/ To get latest informations about Linux Kernel development, please consult the Linux Kernel Mailing List Archives at : - http://boudicca.tux.org/hypermail/linux-kernel/latest/ + http://www.ussg.iu.edu/hypermail/linux/kernel/ -- END -- diff -Nru a/Documentation/networking/ifenslave.c b/Documentation/networking/ifenslave.c --- a/Documentation/networking/ifenslave.c Thu Jan 22 18:59:24 2004 +++ b/Documentation/networking/ifenslave.c Thu Jan 22 18:59:24 2004 @@ -4,8 +4,6 @@ * This program controls the Linux implementation of running multiple * network interfaces in parallel. * - * Usage: ifenslave [-v] master-interface < slave-interface [metric ] > ... - * * Author: Donald Becker * Copyright 1994-1996 Donald Becker * @@ -90,24 +88,30 @@ * - For opt_c: slave should not be set to the master's setting * while it is running. It was already set during enslave. To * simplify things, it is now handeled separately. + * + * - 2003/12/01 - Shmulik Hen + * - Code cleanup and style changes + * set version to 1.1.0 */ -#define APP_VERSION "1.0.12" -#define APP_RELDATE "June 30, 2003" +#define APP_VERSION "1.1.0" +#define APP_RELDATE "December 1, 2003" #define APP_NAME "ifenslave" static char *version = -APP_NAME ".c:v" APP_VERSION " (" APP_RELDATE ") " "\nDonald Becker (becker@cesdis.gsfc.nasa.gov).\n" -"detach support added on 2000/10/02 by Willy Tarreau (willy at meta-x.org).\n" -"2.4 kernel support added on 2001/02/16 by Chad N. Tindel (ctindel at ieee dot org.\n"; +APP_NAME ".c:v" APP_VERSION " (" APP_RELDATE ")\n" +"o Donald Becker (becker@cesdis.gsfc.nasa.gov).\n" +"o Detach support added on 2000/10/02 by Willy Tarreau (willy at meta-x.org).\n" +"o 2.4 kernel support added on 2001/02/16 by Chad N. Tindel\n" +" (ctindel at ieee dot org).\n"; static const char *usage_msg = -"Usage: ifenslave [-adfrvVh] < [metric ] > ...\n" -" ifenslave -c master-interface slave-if\n"; +"Usage: ifenslave [-f] [...]\n" +" ifenslave -d [...]\n" +" ifenslave -c \n" +" ifenslave --help\n"; -static const char *howto_msg = -"Usage: ifenslave [-adfrvVh] < [metric ] > ...\n" -" ifenslave -c master-interface slave-if\n" +static const char *help_msg = "\n" " To create a bond device, simply follow these three steps :\n" " - ensure that the required drivers are properly loaded :\n" @@ -115,18 +119,32 @@ " - assign an IP address to the bond device :\n" " # ifconfig bond0 netmask broadcast \n" " - attach all the interfaces you need to the bond device :\n" -" # ifenslave bond0 eth0 eth1 eth2\n" +" # ifenslave [{-f|--force}] bond0 eth0 [eth1 [eth2]...]\n" " If bond0 didn't have a MAC address, it will take eth0's. Then, all\n" " interfaces attached AFTER this assignment will get the same MAC addr.\n" -"\n" -" To detach a dead interface without setting the bond device down :\n" -" # ifenslave -d bond0 eth1\n" +" (except for ALB/TLB modes)\n" "\n" " To set the bond device down and automatically release all the slaves :\n" " # ifconfig bond0 down\n" "\n" +" To detach a dead interface without setting the bond device down :\n" +" # ifenslave {-d|--detach} bond0 eth0 [eth1 [eth2]...]\n" +"\n" " To change active slave :\n" -" # ifenslave -c bond0 eth0\n" +" # ifenslave {-c|--change-active} bond0 eth0\n" +"\n" +" To show master interface info\n" +" # ifenslave bond0\n" +"\n" +" To show all interfaces info\n" +" # ifenslave {-a|--all-interfaces}\n" +"\n" +" To be more verbose\n" +" # ifenslave {-v|--verbose} ...\n" +"\n" +" # ifenslave {-u|--usage} Show usage\n" +" # ifenslave {-V|--version} Show version\n" +" # ifenslave {-h|--help} This message\n" "\n"; #include @@ -153,476 +171,332 @@ #include struct option longopts[] = { - /* { name has_arg *flag val } */ - {"all-interfaces", 0, 0, 'a'}, /* Show all interfaces. */ - {"force", 0, 0, 'f'}, /* Force the operation. */ - {"help", 0, 0, '?'}, /* Give help */ - {"howto", 0, 0, 'h'}, /* Give some more help */ - {"receive-slave", 0, 0, 'r'}, /* Make a receive-only slave. */ - {"verbose", 0, 0, 'v'}, /* Report each action taken. */ - {"version", 0, 0, 'V'}, /* Emit version information. */ - {"detach", 0, 0, 'd'}, /* Detach a slave interface. */ - {"change-active", 0, 0, 'c'}, /* Change the active slave. */ - { 0, 0, 0, 0 } + /* { name has_arg *flag val } */ + {"all-interfaces", 0, 0, 'a'}, /* Show all interfaces. */ + {"change-active", 0, 0, 'c'}, /* Change the active slave. */ + {"detach", 0, 0, 'd'}, /* Detach a slave interface. */ + {"force", 0, 0, 'f'}, /* Force the operation. */ + {"help", 0, 0, 'h'}, /* Give help */ + {"usage", 0, 0, 'u'}, /* Give usage */ + {"verbose", 0, 0, 'v'}, /* Report each action taken. */ + {"version", 0, 0, 'V'}, /* Emit version information. */ + { 0, 0, 0, 0} }; /* Command-line flags. */ unsigned int -opt_a = 0, /* Show-all-interfaces flag. */ -opt_f = 0, /* Force the operation. */ -opt_r = 0, /* Set up a Rx-only slave. */ -opt_d = 0, /* detach a slave interface. */ -opt_c = 0, /* change-active-slave flag. */ -verbose = 0, /* Verbose flag. */ -opt_version = 0, -opt_howto = 0; -int skfd = -1; /* AF_INET socket for ioctl() calls. */ +opt_a = 0, /* Show-all-interfaces flag. */ +opt_c = 0, /* Change-active-slave flag. */ +opt_d = 0, /* Detach a slave interface. */ +opt_f = 0, /* Force the operation. */ +opt_h = 0, /* Help */ +opt_u = 0, /* Usage */ +opt_v = 0, /* Verbose flag. */ +opt_V = 0; /* Version */ + +int skfd = -1; /* AF_INET socket for ioctl() calls.*/ +int abi_ver = 0; /* userland - kernel ABI version */ +int hwaddr_set = 0; /* Master's hwaddr is set */ +int saved_errno; + +struct ifreq master_mtu, master_flags, master_hwaddr; +struct ifreq slave_mtu, slave_flags, slave_hwaddr; + +struct dev_ifr { + struct ifreq *req_ifr; + char *req_name; + int req_type; +}; + +struct dev_ifr master_ifra[] = { + {&master_mtu, "SIOCGIFMTU", SIOCGIFMTU}, + {&master_flags, "SIOCGIFFLAGS", SIOCGIFFLAGS}, + {&master_hwaddr, "SIOCGIFHWADDR", SIOCGIFHWADDR}, + {NULL, "", 0} +}; + +struct dev_ifr slave_ifra[] = { + {&slave_mtu, "SIOCGIFMTU", SIOCGIFMTU}, + {&slave_flags, "SIOCGIFFLAGS", SIOCGIFFLAGS}, + {&slave_hwaddr, "SIOCGIFHWADDR", SIOCGIFHWADDR}, + {NULL, "", 0} +}; static void if_print(char *ifname); -static int get_abi_ver(char *master_ifname); +static int get_drv_info(char *master_ifname); +static int get_if_settings(char *ifname, struct dev_ifr ifra[]); +static int get_slave_flags(char *slave_ifname); +static int set_master_hwaddr(char *master_ifname, struct sockaddr *hwaddr); +static int set_slave_hwaddr(char *slave_ifname, struct sockaddr *hwaddr); +static int set_slave_mtu(char *slave_ifname, int mtu); +static int set_if_flags(char *ifname, short flags); +static int set_if_up(char *ifname, short flags); +static int set_if_down(char *ifname, short flags); +static int clear_if_addr(char *ifname); +static int set_if_addr(char *master_ifname, char *slave_ifname); +static int change_active(char *master_ifname, char *slave_ifname); +static int enslave(char *master_ifname, char *slave_ifname); +static int release(char *master_ifname, char *slave_ifname); +#define v_print(fmt, args...) \ + if (opt_v) \ + fprintf(stderr, fmt, ## args ) -int -main(int argc, char **argv) +int main(int argc, char *argv[]) { - struct ifreq ifr2, if_hwaddr, if_ipaddr, if_metric, if_mtu, if_dstaddr; - struct ifreq if_netmask, if_brdaddr, if_flags; - int rv, goterr = 0; - int c, errflag = 0; - sa_family_t master_family; char **spp, *master_ifname, *slave_ifname; - int hwaddr_notset; - int abi_ver = 0; + int c, i, rv; + int res = 0; + int exclusive = 0; - while ((c = getopt_long(argc, argv, "acdfrvV?h", longopts, 0)) != EOF) + while ((c = getopt_long(argc, argv, "acdfhuvV", longopts, 0)) != EOF) { switch (c) { - case 'a': opt_a++; break; - case 'f': opt_f++; break; - case 'r': opt_r++; break; - case 'd': opt_d++; break; - case 'c': opt_c++; break; - case 'v': verbose++; break; - case 'V': opt_version++; break; - case 'h': opt_howto++; break; - case '?': errflag++; - } + case 'a': opt_a++; exclusive++; break; + case 'c': opt_c++; exclusive++; break; + case 'd': opt_d++; exclusive++; break; + case 'f': opt_f++; exclusive++; break; + case 'h': opt_h++; exclusive++; break; + case 'u': opt_u++; exclusive++; break; + case 'v': opt_v++; break; + case 'V': opt_V++; exclusive++; break; - /* option check */ - if (opt_c) - if(opt_a || opt_f || opt_r || opt_d || verbose || opt_version || - opt_howto || errflag ) { + case '?': fprintf(stderr, usage_msg); - return 2; + res = 2; + goto out; } + } - if (errflag) { + /* options check */ + if (exclusive > 1) { fprintf(stderr, usage_msg); - return 2; + res = 2; + goto out; } - if (opt_howto) { - fprintf(stderr, howto_msg); - return 0; + if (opt_v || opt_V) { + printf(version); + if (opt_V) { + res = 0; + goto out; + } } - if (verbose || opt_version) { - printf(version); - if (opt_version) - exit(0); + if (opt_u) { + printf(usage_msg); + res = 0; + goto out; } - /* Open a basic socket. */ - if ((skfd = socket(AF_INET, SOCK_DGRAM,0)) < 0) { - perror("socket"); - exit(-1); + if (opt_h) { + printf(usage_msg); + printf(help_msg); + res = 0; + goto out; } - if (verbose) - fprintf(stderr, "DEBUG: argc=%d, optind=%d and argv[optind] is %s.\n", - argc, optind, argv[optind]); + /* Open a basic socket */ + if ((skfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { + perror("socket"); + res = 1; + goto out; + } - /* No remaining args means show all interfaces. */ - if (optind == argc) { - if_print((char *)NULL); - (void) close(skfd); - exit(0); + if (opt_a) { + if (optind == argc) { + /* No remaining args */ + /* show all interfaces */ + if_print((char *)NULL); + goto out; + } else { + /* Just show usage */ + fprintf(stderr, usage_msg); + res = 2; + goto out; + } } - /* Copy the interface name. */ + /* Copy the interface name */ spp = argv + optind; master_ifname = *spp++; - slave_ifname = *spp++; - /* Check command line. */ - if (opt_c) { - char **tempp = spp; - if ((master_ifname == NULL)||(slave_ifname == NULL)||(*tempp++ != NULL)) { - fprintf(stderr, usage_msg); - (void) close(skfd); - return 2; - } + if (master_ifname == NULL) { + fprintf(stderr, usage_msg); + res = 2; + goto out; } - /* A single args means show the configuration for this interface. */ - if (slave_ifname == NULL) { - if_print(master_ifname); - (void) close(skfd); - exit(0); + /* exchange abi version with bonding module */ + res = get_drv_info(master_ifname); + if (res) { + fprintf(stderr, + "Master '%s': Error: handshake with driver failed. " + "Aborting\n", + master_ifname); + goto out; } - /* exchange abi version with bonding driver */ - abi_ver = get_abi_ver(master_ifname); - if (abi_ver < 0) { - (void) close(skfd); - exit(1); - } - - /* Get the vitals from the master interface. */ - { - struct ifreq *ifra[7] = { &if_ipaddr, &if_mtu, &if_dstaddr, - &if_brdaddr, &if_netmask, &if_flags, - &if_hwaddr }; - const char *req_name[7] = { - "IP address", "MTU", "destination address", - "broadcast address", "netmask", "status flags", - "hardware address" }; - const int ioctl_req_type[7] = { - SIOCGIFADDR, SIOCGIFMTU, SIOCGIFDSTADDR, - SIOCGIFBRDADDR, SIOCGIFNETMASK, SIOCGIFFLAGS, - SIOCGIFHWADDR }; - int i; - - for (i = 0; i < 7; i++) { - strncpy(ifra[i]->ifr_name, master_ifname, IFNAMSIZ); - if (ioctl(skfd, ioctl_req_type[i], ifra[i]) < 0) { - fprintf(stderr, - "Something broke getting the master's %s: %s.\n", - req_name[i], strerror(errno)); - } - } - - /* check if master is up; if not then fail any operation */ - if (!(if_flags.ifr_flags & IFF_UP)) { - fprintf(stderr, "Illegal operation; the specified master interface '%s' is not up.\n", master_ifname); - (void) close(skfd); - exit (1); - } + slave_ifname = *spp++; - hwaddr_notset = 1; /* assume master's address not set yet */ - for (i = 0; hwaddr_notset && (i < 6); i++) { - hwaddr_notset &= ((unsigned char *)if_hwaddr.ifr_hwaddr.sa_data)[i] == 0; + if (slave_ifname == NULL) { + if (opt_d || opt_c) { + fprintf(stderr, usage_msg); + res = 2; + goto out; } - /* The family '1' is ARPHRD_ETHER for ethernet. */ - if (if_hwaddr.ifr_hwaddr.sa_family != 1 && !opt_f) { - fprintf(stderr, "The specified master interface '%s' is not" - " ethernet-like.\n This program is designed to work" - " with ethernet-like network interfaces.\n" - " Use the '-f' option to force the operation.\n", - master_ifname); - (void) close(skfd); - exit (1); - } - master_family = if_hwaddr.ifr_hwaddr.sa_family; - if (verbose) { - unsigned char *hwaddr = (unsigned char *)if_hwaddr.ifr_hwaddr.sa_data; - printf("The current hardware address (SIOCGIFHWADDR) of %s is type %d " - "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x.\n", master_ifname, - if_hwaddr.ifr_hwaddr.sa_family, hwaddr[0], hwaddr[1], - hwaddr[2], hwaddr[3], hwaddr[4], hwaddr[5]); - } + /* A single arg means show the + * configuration for this interface + */ + if_print(master_ifname); + goto out; } + res = get_if_settings(master_ifname, master_ifra); + if (res) { + /* Probably a good reason not to go on */ + fprintf(stderr, + "Master '%s': Error: get settings failed: %s. " + "Aborting\n", + master_ifname, strerror(res)); + goto out; + } - /* do this when enslaving interfaces */ - do { - if (opt_d) { /* detach a slave interface from the master */ - strncpy(if_flags.ifr_name, master_ifname, IFNAMSIZ); - strncpy(if_flags.ifr_slave, slave_ifname, IFNAMSIZ); - if ((ioctl(skfd, SIOCBONDRELEASE, &if_flags) < 0) && - (ioctl(skfd, BOND_RELEASE_OLD, &if_flags) < 0)) { - fprintf(stderr, "SIOCBONDRELEASE: cannot detach %s from %s. errno=%s.\n", - slave_ifname, master_ifname, strerror(errno)); - } - else if (abi_ver < 1) { - /* The driver is using an old ABI, so we'll set the interface - * down to avoid any conflicts due to same IP/MAC - */ - strncpy(ifr2.ifr_name, slave_ifname, IFNAMSIZ); - if (ioctl(skfd, SIOCGIFFLAGS, &ifr2) < 0) { - int saved_errno = errno; - fprintf(stderr, "SIOCGIFFLAGS on %s failed: %s\n", slave_ifname, - strerror(saved_errno)); - } - else { - ifr2.ifr_flags &= ~(IFF_UP | IFF_RUNNING); - if (ioctl(skfd, SIOCSIFFLAGS, &ifr2) < 0) { - int saved_errno = errno; - fprintf(stderr, "Shutting down interface %s failed: %s\n", - slave_ifname, strerror(saved_errno)); - } - } - } - } else if (opt_c) { /* change primary slave */ - strncpy(if_flags.ifr_name, master_ifname, IFNAMSIZ); - strncpy(if_flags.ifr_slave, slave_ifname, IFNAMSIZ); - if ((ioctl(skfd, SIOCBONDCHANGEACTIVE, &if_flags) < 0) && - (ioctl(skfd, BOND_CHANGE_ACTIVE_OLD, &if_flags) < 0)) { - fprintf(stderr, "SIOCBONDCHANGEACTIVE: %s.\n", strerror(errno)); - } - } else { /* attach a slave interface to the master */ - - strncpy(ifr2.ifr_name, slave_ifname, IFNAMSIZ); - if (ioctl(skfd, SIOCGIFFLAGS, &ifr2) < 0) { - int saved_errno = errno; - fprintf(stderr, "SIOCGIFFLAGS on %s failed: %s\n", slave_ifname, - strerror(saved_errno)); - (void) close(skfd); - return 1; - } - - if ((ifr2.ifr_flags & IFF_SLAVE) && !opt_r) { - fprintf(stderr, "%s is already a slave\n", slave_ifname); - (void) close(skfd); - return 1; - } - - /* if hwaddr_notset, assign the slave hw address to the master */ - if (hwaddr_notset) { - /* assign the slave hw address to the - * master since it currently does not - * have one; otherwise, slaves may - * have different hw addresses in - * active-backup mode as seen when enslaving - * using "ifenslave bond0 eth0 eth1" because - * hwaddr_notset is set outside this loop. - * TODO: put this and the "else" portion in - * a function. - */ - /* get the slaves MAC address */ - strncpy(if_hwaddr.ifr_name, slave_ifname, - IFNAMSIZ); - rv = ioctl(skfd, SIOCGIFHWADDR, &if_hwaddr); - if (-1 == rv) { - fprintf(stderr, "Could not get MAC " - "address of %s: %s\n", - slave_ifname, - strerror(errno)); - strncpy(if_hwaddr.ifr_name, - master_ifname, IFNAMSIZ); - goterr = 1; - } - - if (!goterr) { - if (abi_ver < 1) { - /* In ABI versions older than 1, the - * master's set_mac routine couldn't - * work if it was up, because it - * used the default ethernet set_mac - * function. - */ - /* bring master down */ - if_flags.ifr_flags &= ~IFF_UP; - if (ioctl(skfd, SIOCSIFFLAGS, - &if_flags) < 0) { - goterr = 1; - fprintf(stderr, - "Shutting down " - "interface %s failed: " - "%s\n", - master_ifname, - strerror(errno)); - } - } - - strncpy(if_hwaddr.ifr_name, - master_ifname, IFNAMSIZ); - if (ioctl(skfd, SIOCSIFHWADDR, - &if_hwaddr) < 0) { - fprintf(stderr, - "Could not set MAC " - "address of %s: %s\n", - master_ifname, - strerror(errno)); - goterr=1; - } else { - hwaddr_notset = 0; - } - - if (abi_ver < 1) { - /* bring master back up */ - if_flags.ifr_flags |= IFF_UP; - if (ioctl(skfd, SIOCSIFFLAGS, - &if_flags) < 0) { - fprintf(stderr, - "Bringing up interface " - "%s failed: %s\n", - master_ifname, - strerror(errno)); - } - } - } - } else if (abi_ver < 1) { /* if (hwaddr_notset) */ - - /* The driver is using an old ABI, so we'll set the interface - * down and assign the master's hwaddr to it - */ - if (ifr2.ifr_flags & IFF_UP) { - ifr2.ifr_flags &= ~IFF_UP; - if (ioctl(skfd, SIOCSIFFLAGS, &ifr2) < 0) { - int saved_errno = errno; - fprintf(stderr, "Shutting down interface %s failed: %s\n", - slave_ifname, strerror(saved_errno)); - } - } - - strncpy(if_hwaddr.ifr_name, slave_ifname, IFNAMSIZ); - if (ioctl(skfd, SIOCSIFHWADDR, &if_hwaddr) < 0) { - int saved_errno = errno; - fprintf(stderr, "SIOCSIFHWADDR on %s failed: %s\n", if_hwaddr.ifr_name, - strerror(saved_errno)); - if (saved_errno == EBUSY) - fprintf(stderr, " The slave device %s is busy: it must be" - " idle before running this command.\n", slave_ifname); - else if (saved_errno == EOPNOTSUPP) - fprintf(stderr, " The slave device you specified does not support" - " setting the MAC address.\n Your kernel likely does not" - " support slave devices.\n"); - else if (saved_errno == EINVAL) - fprintf(stderr, " The slave device's address type does not match" - " the master's address type.\n"); - } else { - if (verbose) { - unsigned char *hwaddr = if_hwaddr.ifr_hwaddr.sa_data; - printf("Slave's (%s) hardware address set to " - "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x.\n", slave_ifname, - hwaddr[0], hwaddr[1], hwaddr[2], hwaddr[3], hwaddr[4], hwaddr[5]); - } - } - } + /* check if master is indeed a master; + * if not then fail any operation + */ + if (!(master_flags.ifr_flags & IFF_MASTER)) { + fprintf(stderr, + "Illegal operation; the specified interface '%s' " + "is not a master. Aborting\n", + master_ifname); + res = 1; + goto out; + } - if (*spp && !strcmp(*spp, "metric")) { - if (*++spp == NULL) { - fprintf(stderr, usage_msg); - (void) close(skfd); - exit(2); - } - if_metric.ifr_metric = atoi(*spp); - strncpy(if_metric.ifr_name, slave_ifname, IFNAMSIZ); - if (ioctl(skfd, SIOCSIFMETRIC, &if_metric) < 0) { - fprintf(stderr, "SIOCSIFMETRIC on %s: %s\n", slave_ifname, - strerror(errno)); - goterr = 1; - } - spp++; - } + /* check if master is up; if not then fail any operation */ + if (!(master_flags.ifr_flags & IFF_UP)) { + fprintf(stderr, + "Illegal operation; the specified master interface " + "'%s' is not up.\n", + master_ifname); + res = 1; + goto out; + } - if (strncpy(if_ipaddr.ifr_name, slave_ifname, IFNAMSIZ) <= 0 - || ioctl(skfd, SIOCSIFADDR, &if_ipaddr) < 0) { - fprintf(stderr, - "Something broke setting the slave's address: %s.\n", - strerror(errno)); - } else { - if (verbose) { - unsigned char *ipaddr = if_ipaddr.ifr_addr.sa_data; - printf("Set the slave's (%s) IP address to %d.%d.%d.%d.\n", - slave_ifname, ipaddr[0], ipaddr[1], ipaddr[2], ipaddr[3]); - } - } + /* Only for enslaving */ + if (!opt_c && !opt_d) { + sa_family_t master_family = master_hwaddr.ifr_hwaddr.sa_family; + unsigned char *hwaddr = + (unsigned char *)master_hwaddr.ifr_hwaddr.sa_data; - if (strncpy(if_mtu.ifr_name, slave_ifname, IFNAMSIZ) <= 0 - || ioctl(skfd, SIOCSIFMTU, &if_mtu) < 0) { - fprintf(stderr, "Something broke setting the slave MTU: %s.\n", - strerror(errno)); - } else { - if (verbose) - printf("Set the slave's (%s) MTU to %d.\n", slave_ifname, if_mtu.ifr_mtu); - } + /* The family '1' is ARPHRD_ETHER for ethernet. */ + if (master_family != 1 && !opt_f) { + fprintf(stderr, + "Illegal operation: The specified master " + "interface '%s' is not ethernet-like.\n " + "This program is designed to work with " + "ethernet-like network interfaces.\n " + "Use the '-f' option to force the " + "operation.\n", + master_ifname); + res = 1; + goto out; + } - if (strncpy(if_dstaddr.ifr_name, slave_ifname, IFNAMSIZ) <= 0 - || ioctl(skfd, SIOCSIFDSTADDR, &if_dstaddr) < 0) { - fprintf(stderr, "Error setting the slave (%s) with SIOCSIFDSTADDR: %s.\n", - slave_ifname, strerror(errno)); - } else { - if (verbose) { - unsigned char *ipaddr = if_dstaddr.ifr_dstaddr.sa_data; - printf("Set the slave's (%s) destination address to %d.%d.%d.%d.\n", - slave_ifname, ipaddr[0], ipaddr[1], ipaddr[2], ipaddr[3]); - } + /* Check master's hw addr */ + for (i = 0; i < 6; i++) { + if (hwaddr[i] != 0) { + hwaddr_set = 1; + break; } + } - if (strncpy(if_brdaddr.ifr_name, slave_ifname, IFNAMSIZ) <= 0 - || ioctl(skfd, SIOCSIFBRDADDR, &if_brdaddr) < 0) { - fprintf(stderr, - "Something broke setting the slave (%s) broadcast address: %s.\n", - slave_ifname, strerror(errno)); - } else { - if (verbose) { - unsigned char *ipaddr = if_brdaddr.ifr_broadaddr.sa_data; - printf("Set the slave's (%s) broadcast address to %d.%d.%d.%d.\n", - slave_ifname, ipaddr[0], ipaddr[1], ipaddr[2], ipaddr[3]); - } - } + if (hwaddr_set) { + v_print("current hardware address of master '%s' " + "is %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x, " + "type %d\n", + master_ifname, + hwaddr[0], hwaddr[1], + hwaddr[2], hwaddr[3], + hwaddr[4], hwaddr[5], + master_family); + } + } - if (strncpy(if_netmask.ifr_name, slave_ifname, IFNAMSIZ) <= 0 - || ioctl(skfd, SIOCSIFNETMASK, &if_netmask) < 0) { - fprintf(stderr, - "Something broke setting the slave (%s) netmask: %s.\n", - slave_ifname, strerror(errno)); - } else { - if (verbose) { - unsigned char *ipaddr = if_netmask.ifr_netmask.sa_data; - printf("Set the slave's (%s) netmask to %d.%d.%d.%d.\n", - slave_ifname, ipaddr[0], ipaddr[1], ipaddr[2], ipaddr[3]); + /* Accepts only one slave */ + if (opt_c) { + /* change active slave */ + res = get_slave_flags(slave_ifname); + if (res) { + fprintf(stderr, + "Slave '%s': Error: get flags failed. " + "Aborting\n", + slave_ifname); + goto out; + } + res = change_active(master_ifname, slave_ifname); + if (res) { + fprintf(stderr, + "Master '%s', Slave '%s': Error: " + "Change active failed\n", + master_ifname, slave_ifname); + } + } else { + /* Accept multiple slaves */ + do { + if (opt_d) { + /* detach a slave interface from the master */ + rv = get_slave_flags(slave_ifname); + if (rv) { + /* Can't work with this slave. */ + /* remember the error and skip it*/ + fprintf(stderr, + "Slave '%s': Error: get flags " + "failed. Skipping\n", + slave_ifname); + res = rv; + continue; } - } - - if (abi_ver < 1) { - - /* The driver is using an old ABI, so we'll set the interface - * up before enslaving it - */ - ifr2.ifr_flags |= IFF_UP; - if ((ifr2.ifr_flags &= ~(IFF_SLAVE | IFF_MASTER)) == 0 - || strncpy(ifr2.ifr_name, slave_ifname, IFNAMSIZ) <= 0 - || ioctl(skfd, SIOCSIFFLAGS, &ifr2) < 0) { - fprintf(stderr, - "Something broke setting the slave (%s) flags: %s.\n", - slave_ifname, strerror(errno)); - } else { - if (verbose) - printf("Set the slave's (%s) flags %4.4x.\n", - slave_ifname, if_flags.ifr_flags); + rv = release(master_ifname, slave_ifname); + if (rv) { + fprintf(stderr, + "Master '%s', Slave '%s': Error: " + "Release failed\n", + master_ifname, slave_ifname); + res = rv; } } else { - /* the bonding module takes care of setting the slave's mac address - * and opening its interface - */ - if (ifr2.ifr_flags & IFF_UP) { /* the interface will need to be down */ - ifr2.ifr_flags &= ~IFF_UP; - if (ioctl(skfd, SIOCSIFFLAGS, &ifr2) < 0) { - int saved_errno = errno; - fprintf(stderr, "Shutting down interface %s failed: %s\n", - slave_ifname, strerror(saved_errno)); - } + /* attach a slave interface to the master */ + rv = get_if_settings(slave_ifname, slave_ifra); + if (rv) { + /* Can't work with this slave. */ + /* remember the error and skip it*/ + fprintf(stderr, + "Slave '%s': Error: get " + "settings failed: %s. " + "Skipping\n", + slave_ifname, strerror(rv)); + res = rv; + continue; } - } - - /* Do the real thing */ - if (!opt_r) { - strncpy(if_flags.ifr_name, master_ifname, IFNAMSIZ); - strncpy(if_flags.ifr_slave, slave_ifname, IFNAMSIZ); - if ((ioctl(skfd, SIOCBONDENSLAVE, &if_flags) < 0) && - (ioctl(skfd, BOND_ENSLAVE_OLD, &if_flags) < 0)) { - fprintf(stderr, "SIOCBONDENSLAVE: %s.\n", strerror(errno)); + rv = enslave(master_ifname, slave_ifname); + if (rv) { + fprintf(stderr, + "Master '%s', Slave '%s': Error: " + "Enslave failed\n", + master_ifname, slave_ifname); + res = rv; } } - } - } while ( (slave_ifname = *spp++) != NULL); + } while ((slave_ifname = *spp++) != NULL); + } - /* Close the socket. */ - (void) close(skfd); +out: + if (skfd >= 0) { + close(skfd); + } - return(goterr); + return res; } static short mif_flags; @@ -631,35 +505,34 @@ static int if_getconfig(char *ifname) { struct ifreq ifr; - int metric, mtu; /* Parameters of the master interface. */ + int metric, mtu; /* Parameters of the master interface. */ struct sockaddr dstaddr, broadaddr, netmask; + unsigned char *hwaddr; strcpy(ifr.ifr_name, ifname); if (ioctl(skfd, SIOCGIFFLAGS, &ifr) < 0) return -1; mif_flags = ifr.ifr_flags; printf("The result of SIOCGIFFLAGS on %s is %x.\n", - ifname, ifr.ifr_flags); + ifname, ifr.ifr_flags); strcpy(ifr.ifr_name, ifname); if (ioctl(skfd, SIOCGIFADDR, &ifr) < 0) return -1; printf("The result of SIOCGIFADDR is %2.2x.%2.2x.%2.2x.%2.2x.\n", - ifr.ifr_addr.sa_data[0], ifr.ifr_addr.sa_data[1], - ifr.ifr_addr.sa_data[2], ifr.ifr_addr.sa_data[3]); + ifr.ifr_addr.sa_data[0], ifr.ifr_addr.sa_data[1], + ifr.ifr_addr.sa_data[2], ifr.ifr_addr.sa_data[3]); strcpy(ifr.ifr_name, ifname); if (ioctl(skfd, SIOCGIFHWADDR, &ifr) < 0) return -1; - { - /* Gotta convert from 'char' to unsigned for printf(). */ - unsigned char *hwaddr = (unsigned char *)ifr.ifr_hwaddr.sa_data; - printf("The result of SIOCGIFHWADDR is type %d " - "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x.\n", - ifr.ifr_hwaddr.sa_family, hwaddr[0], hwaddr[1], - hwaddr[2], hwaddr[3], hwaddr[4], hwaddr[5]); - } + /* Gotta convert from 'char' to unsigned for printf(). */ + hwaddr = (unsigned char *)ifr.ifr_hwaddr.sa_data; + printf("The result of SIOCGIFHWADDR is type %d " + "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x.\n", + ifr.ifr_hwaddr.sa_family, hwaddr[0], hwaddr[1], + hwaddr[2], hwaddr[3], hwaddr[4], hwaddr[5]); strcpy(ifr.ifr_name, ifname); if (ioctl(skfd, SIOCGIFMETRIC, &ifr) < 0) { @@ -691,7 +564,7 @@ } else netmask = ifr.ifr_netmask; - return(0); + return 0; } static void if_print(char *ifname) @@ -705,15 +578,16 @@ ifc.ifc_len = sizeof(buff); ifc.ifc_buf = buff; if (ioctl(skfd, SIOCGIFCONF, &ifc) < 0) { - fprintf(stderr, "SIOCGIFCONF: %s\n", strerror(errno)); + perror("SIOCGIFCONF failed"); return; } ifr = ifc.ifc_req; for (i = ifc.ifc_len / sizeof(struct ifreq); --i >= 0; ifr++) { if (if_getconfig(ifr->ifr_name) < 0) { - fprintf(stderr, "%s: unknown interface.\n", - ifr->ifr_name); + fprintf(stderr, + "%s: unknown interface.\n", + ifr->ifr_name); continue; } @@ -721,16 +595,18 @@ /*ife_print(&ife);*/ } } else { - if (if_getconfig(ifname) < 0) - fprintf(stderr, "%s: unknown interface.\n", ifname); + if (if_getconfig(ifname) < 0) { + fprintf(stderr, + "%s: unknown interface.\n", ifname); + } } } -static int get_abi_ver(char *master_ifname) +static int get_drv_info(char *master_ifname) { struct ifreq ifr; struct ethtool_drvinfo info; - int abi_ver = 0; + char *endptr; memset(&ifr, 0, sizeof(ifr)); strncpy(ifr.ifr_name, master_ifname, IFNAMSIZ); @@ -739,24 +615,487 @@ info.cmd = ETHTOOL_GDRVINFO; strncpy(info.driver, "ifenslave", 32); snprintf(info.fw_version, 32, "%d", BOND_ABI_VERSION); - if (ioctl(skfd, SIOCETHTOOL, &ifr) >= 0) { - char *endptr; - abi_ver = strtoul(info.fw_version, &endptr, 0); - if (*endptr) { - fprintf(stderr, "Error: got invalid string as an ABI " - "version from the bonding module\n"); - return -1; + if (ioctl(skfd, SIOCETHTOOL, &ifr) < 0) { + if (errno == EOPNOTSUPP) { + goto out; } + + saved_errno = errno; + v_print("Master '%s': Error: get bonding info failed %s\n", + master_ifname, strerror(saved_errno)); + return 1; } - if (verbose) { - printf("ABI ver is %d\n", abi_ver); + abi_ver = strtoul(info.fw_version, &endptr, 0); + if (*endptr) { + v_print("Master '%s': Error: got invalid string as an ABI " + "version from the bonding module\n", + master_ifname); + return 1; } - return abi_ver; + +out: + v_print("ABI ver is %d\n", abi_ver); + + return 0; } +static int change_active(char *master_ifname, char *slave_ifname) +{ + struct ifreq ifr; + int res = 0; + if (!(slave_flags.ifr_flags & IFF_SLAVE)) { + fprintf(stderr, + "Illegal operation: The specified slave interface " + "'%s' is not a slave\n", + slave_ifname); + return 1; + } + + strncpy(ifr.ifr_name, master_ifname, IFNAMSIZ); + strncpy(ifr.ifr_slave, slave_ifname, IFNAMSIZ); + if ((ioctl(skfd, SIOCBONDCHANGEACTIVE, &ifr) < 0) && + (ioctl(skfd, BOND_CHANGE_ACTIVE_OLD, &ifr) < 0)) { + saved_errno = errno; + v_print("Master '%s': Error: SIOCBONDCHANGEACTIVE failed: " + "%s\n", + master_ifname, strerror(saved_errno)); + res = 1; + } + + return res; +} + +static int enslave(char *master_ifname, char *slave_ifname) +{ + struct ifreq ifr; + int res = 0; + + if (slave_flags.ifr_flags & IFF_SLAVE) { + fprintf(stderr, + "Illegal operation: The specified slave interface " + "'%s' is already a slave\n", + slave_ifname); + return 1; + } + + res = set_if_down(slave_ifname, slave_flags.ifr_flags); + if (res) { + fprintf(stderr, + "Slave '%s': Error: bring interface down failed\n", + slave_ifname); + return res; + } + + if (abi_ver < 2) { + /* Older bonding versions would panic if the slave has no IP + * address, so get the IP setting from the master. + */ + res = set_if_addr(master_ifname, slave_ifname); + if (res) { + fprintf(stderr, + "Slave '%s': Error: set address failed\n", + slave_ifname); + return res; + } + } else { + res = clear_if_addr(slave_ifname); + if (res) { + fprintf(stderr, + "Slave '%s': Error: clear address failed\n", + slave_ifname); + return res; + } + } + + if (master_mtu.ifr_mtu != slave_mtu.ifr_mtu) { + res = set_slave_mtu(slave_ifname, master_mtu.ifr_mtu); + if (res) { + fprintf(stderr, + "Slave '%s': Error: set MTU failed\n", + slave_ifname); + return res; + } + } + + if (hwaddr_set) { + /* Master already has an hwaddr + * so set it's hwaddr to the slave + */ + if (abi_ver < 1) { + /* The driver is using an old ABI, so + * the application sets the slave's + * hwaddr + */ + res = set_slave_hwaddr(slave_ifname, + &(master_hwaddr.ifr_hwaddr)); + if (res) { + fprintf(stderr, + "Slave '%s': Error: set hw address " + "failed\n", + slave_ifname); + goto undo_mtu; + } + + /* For old ABI the application needs to bring the + * slave back up + */ + res = set_if_up(slave_ifname, slave_flags.ifr_flags); + if (res) { + fprintf(stderr, + "Slave '%s': Error: bring interface " + "down failed\n", + slave_ifname); + goto undo_slave_mac; + } + } + /* The driver is using a new ABI, + * so the driver takes care of setting + * the slave's hwaddr and bringing + * it up again + */ + } else { + /* No hwaddr for master yet, so + * set the slave's hwaddr to it + */ + if (abi_ver < 1) { + /* For old ABI, the master needs to be + * down before setting it's hwaddr + */ + res = set_if_down(master_ifname, master_flags.ifr_flags); + if (res) { + fprintf(stderr, + "Master '%s': Error: bring interface " + "down failed\n", + master_ifname); + goto undo_mtu; + } + } + + res = set_master_hwaddr(master_ifname, + &(slave_hwaddr.ifr_hwaddr)); + if (res) { + fprintf(stderr, + "Master '%s': Error: set hw address " + "failed\n", + master_ifname); + goto undo_mtu; + } + + if (abi_ver < 1) { + /* For old ABI, bring the master + * back up + */ + res = set_if_up(master_ifname, master_flags.ifr_flags); + if (res) { + fprintf(stderr, + "Master '%s': Error: bring interface " + "up failed\n", + master_ifname); + goto undo_master_mac; + } + } + + hwaddr_set = 1; + } + + /* Do the real thing */ + strncpy(ifr.ifr_name, master_ifname, IFNAMSIZ); + strncpy(ifr.ifr_slave, slave_ifname, IFNAMSIZ); + if ((ioctl(skfd, SIOCBONDENSLAVE, &ifr) < 0) && + (ioctl(skfd, BOND_ENSLAVE_OLD, &ifr) < 0)) { + saved_errno = errno; + v_print("Master '%s': Error: SIOCBONDENSLAVE failed: %s\n", + master_ifname, strerror(saved_errno)); + res = 1; + } + + if (res) { + goto undo_master_mac; + } + + return 0; + +/* rollback (best effort) */ +undo_master_mac: + set_master_hwaddr(master_ifname, &(master_hwaddr.ifr_hwaddr)); + hwaddr_set = 0; + goto undo_mtu; +undo_slave_mac: + set_slave_hwaddr(slave_ifname, &(slave_hwaddr.ifr_hwaddr)); +undo_mtu: + set_slave_mtu(slave_ifname, slave_mtu.ifr_mtu); + return res; +} + +static int release(char *master_ifname, char *slave_ifname) +{ + struct ifreq ifr; + int res = 0; + + if (!(slave_flags.ifr_flags & IFF_SLAVE)) { + fprintf(stderr, + "Illegal operation: The specified slave interface " + "'%s' is not a slave\n", + slave_ifname); + return 1; + } + + strncpy(ifr.ifr_name, master_ifname, IFNAMSIZ); + strncpy(ifr.ifr_slave, slave_ifname, IFNAMSIZ); + if ((ioctl(skfd, SIOCBONDRELEASE, &ifr) < 0) && + (ioctl(skfd, BOND_RELEASE_OLD, &ifr) < 0)) { + saved_errno = errno; + v_print("Master '%s': Error: SIOCBONDRELEASE failed: %s\n", + master_ifname, strerror(saved_errno)); + return 1; + } else if (abi_ver < 1) { + /* The driver is using an old ABI, so we'll set the interface + * down to avoid any conflicts due to same MAC/IP + */ + res = set_if_down(slave_ifname, slave_flags.ifr_flags); + if (res) { + fprintf(stderr, + "Slave '%s': Error: bring interface " + "down failed\n", + slave_ifname); + } + } + + /* set to default mtu */ + set_slave_mtu(slave_ifname, 1500); + + return res; +} + +static int get_if_settings(char *ifname, struct dev_ifr ifra[]) +{ + int i; + int res = 0; + + for (i = 0; ifra[i].req_ifr; i++) { + strncpy(ifra[i].req_ifr->ifr_name, ifname, IFNAMSIZ); + res = ioctl(skfd, ifra[i].req_type, ifra[i].req_ifr); + if (res < 0) { + saved_errno = errno; + v_print("Interface '%s': Error: %s failed: %s\n", + ifname, ifra[i].req_name, + strerror(saved_errno)); + + return saved_errno; + } + } + + return 0; +} + +static int get_slave_flags(char *slave_ifname) +{ + int res = 0; + + strncpy(slave_flags.ifr_name, slave_ifname, IFNAMSIZ); + res = ioctl(skfd, SIOCGIFFLAGS, &slave_flags); + if (res < 0) { + saved_errno = errno; + v_print("Slave '%s': Error: SIOCGIFFLAGS failed: %s\n", + slave_ifname, strerror(saved_errno)); + } else { + v_print("Slave %s: flags %04X.\n", + slave_ifname, slave_flags.ifr_flags); + } + + return res; +} + +static int set_master_hwaddr(char *master_ifname, struct sockaddr *hwaddr) +{ + unsigned char *addr = (unsigned char *)hwaddr->sa_data; + struct ifreq ifr; + int res = 0; + + strncpy(ifr.ifr_name, master_ifname, IFNAMSIZ); + memcpy(&(ifr.ifr_hwaddr), hwaddr, sizeof(struct sockaddr)); + res = ioctl(skfd, SIOCSIFHWADDR, &ifr); + if (res < 0) { + saved_errno = errno; + v_print("Master '%s': Error: SIOCSIFHWADDR failed: %s\n", + master_ifname, strerror(saved_errno)); + return res; + } else { + v_print("Master '%s': hardware address set to " + "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x.\n", + master_ifname, addr[0], addr[1], addr[2], + addr[3], addr[4], addr[5]); + } + + return res; +} + +static int set_slave_hwaddr(char *slave_ifname, struct sockaddr *hwaddr) +{ + unsigned char *addr = (unsigned char *)hwaddr->sa_data; + struct ifreq ifr; + int res = 0; + + strncpy(ifr.ifr_name, slave_ifname, IFNAMSIZ); + memcpy(&(ifr.ifr_hwaddr), hwaddr, sizeof(struct sockaddr)); + res = ioctl(skfd, SIOCSIFHWADDR, &ifr); + if (res < 0) { + saved_errno = errno; + + v_print("Slave '%s': Error: SIOCSIFHWADDR failed: %s\n", + slave_ifname, strerror(saved_errno)); + + if (saved_errno == EBUSY) { + v_print(" The device is busy: it must be idle " + "before running this command.\n"); + } else if (saved_errno == EOPNOTSUPP) { + v_print(" The device does not support setting " + "the MAC address.\n" + " Your kernel likely does not support slave " + "devices.\n"); + } else if (saved_errno == EINVAL) { + v_print(" The device's address type does not match " + "the master's address type.\n"); + } + return res; + } else { + v_print("Slave '%s': hardware address set to " + "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x.\n", + slave_ifname, addr[0], addr[1], addr[2], + addr[3], addr[4], addr[5]); + } + + return res; +} + +static int set_slave_mtu(char *slave_ifname, int mtu) +{ + struct ifreq ifr; + int res = 0; + + ifr.ifr_mtu = mtu; + strncpy(ifr.ifr_name, slave_ifname, IFNAMSIZ); + + res = ioctl(skfd, SIOCSIFMTU, &ifr); + if (res < 0) { + saved_errno = errno; + v_print("Slave '%s': Error: SIOCSIFMTU failed: %s\n", + slave_ifname, strerror(saved_errno)); + } else { + v_print("Slave '%s': MTU set to %d.\n", slave_ifname, mtu); + } + + return res; +} + +static int set_if_flags(char *ifname, short flags) +{ + struct ifreq ifr; + int res = 0; + + ifr.ifr_flags = flags; + strncpy(ifr.ifr_name, ifname, IFNAMSIZ); + + res = ioctl(skfd, SIOCSIFFLAGS, &ifr); + if (res < 0) { + saved_errno = errno; + v_print("Interface '%s': Error: SIOCSIFFLAGS failed: %s\n", + ifname, strerror(saved_errno)); + } else { + v_print("Interface '%s': flags set to %04X.\n", ifname, flags); + } + + return res; +} + +static int set_if_up(char *ifname, short flags) +{ + return set_if_flags(ifname, flags | IFF_UP); +} + +static int set_if_down(char *ifname, short flags) +{ + return set_if_flags(ifname, flags & ~IFF_UP); +} + +static int clear_if_addr(char *ifname) +{ + struct ifreq ifr; + int res = 0; + + strncpy(ifr.ifr_name, ifname, IFNAMSIZ); + ifr.ifr_addr.sa_family = AF_INET; + memset(ifr.ifr_addr.sa_data, 0, sizeof(ifr.ifr_addr.sa_data)); + + res = ioctl(skfd, SIOCSIFADDR, &ifr); + if (res < 0) { + saved_errno = errno; + v_print("Interface '%s': Error: SIOCSIFADDR failed: %s\n", + ifname, strerror(saved_errno)); + } else { + v_print("Interface '%s': address cleared\n", ifname); + } + + return res; +} + +static int set_if_addr(char *master_ifname, char *slave_ifname) +{ + struct ifreq ifr; + int res; + unsigned char *ipaddr; + int i; + struct { + char *req_name; + char *desc; + int g_ioctl; + int s_ioctl; + } ifra[] = { + {"IFADDR", "addr", SIOCGIFADDR, SIOCSIFADDR}, + {"DSTADDR", "destination addr", SIOCGIFDSTADDR, SIOCSIFDSTADDR}, + {"BRDADDR", "broadcast addr", SIOCGIFBRDADDR, SIOCSIFBRDADDR}, + {"NETMASK", "netmask", SIOCGIFNETMASK, SIOCSIFNETMASK}, + {NULL, NULL, 0, 0}, + }; + + for (i = 0; ifra[i].req_name; i++) { + strncpy(ifr.ifr_name, master_ifname, IFNAMSIZ); + res = ioctl(skfd, ifra[i].g_ioctl, &ifr); + if (res < 0) { + int saved_errno = errno; + + v_print("Interface '%s': Error: SIOCG%s failed: %s\n", + master_ifname, ifra[i].req_name, + strerror(saved_errno)); + + ifr.ifr_addr.sa_family = AF_INET; + memset(ifr.ifr_addr.sa_data, 0, + sizeof(ifr.ifr_addr.sa_data)); + } + + strncpy(ifr.ifr_name, slave_ifname, IFNAMSIZ); + res = ioctl(skfd, ifra[i].s_ioctl, &ifr); + if (res < 0) { + int saved_errno = errno; + + v_print("Interface '%s': Error: SIOCS%s failed: %s\n", + slave_ifname, ifra[i].req_name, + strerror(saved_errno)); + + return res; + } + + ipaddr = ifr.ifr_addr.sa_data; + v_print("Interface '%s': set IP %s to %d.%d.%d.%d\n", + slave_ifname, ifra[i].desc, + ipaddr[0], ipaddr[1], ipaddr[2], ipaddr[3]); + } + + return 0; +} /* * Local variables: @@ -768,3 +1107,4 @@ * compile-command: "gcc -Wall -Wstrict-prototypes -O -I/usr/src/linux/include ifenslave.c -o ifenslave" * End: */ + diff -Nru a/Documentation/networking/netconsole.txt b/Documentation/networking/netconsole.txt --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/Documentation/networking/netconsole.txt Thu Jan 22 18:59:27 2004 @@ -0,0 +1,57 @@ + +started by Ingo Molnar , 2001.09.17 +2.6 port and netpoll api by Matt Mackall , Sep 9 2003 + +Please send bug reports to Matt Mackall + +This module logs kernel printk messages over UDP allowing debugging of +problem where disk logging fails and serial consoles are impractical. + +It can be used either built-in or as a module. As a built-in, +netconsole initializes immediately after NIC cards and will bring up +the specified interface as soon as possible. While this doesn't allow +capture of early kernel panics, it does capture most of the boot +process. + +It takes a string configuration parameter "netconsole" in the +following format: + + netconsole=[src-port]@[src-ip]/[],[tgt-port]@/[tgt-macaddr] + + where + src-port source for UDP packets (defaults to 6665) + src-ip source IP to use (interface address) + dev network interface (eth0) + tgt-port port for logging agent (6666) + tgt-ip IP address for logging agent + tgt-macaddr ethernet MAC address for logging agent (broadcast) + +Examples: + + linux netconsole=4444@10.0.0.1/eth1,9353@10.0.0.2/12:34:56:78:9a:bc + + or + + insmod netconsole netconsole=@/,@10.0.0.2/ + +Built-in netconsole starts immediately after the TCP stack is +initialized and attempts to bring up the supplied dev at the supplied +address. + +The remote host can run either 'netcat -u -l -p ' or syslogd. + +WARNING: the default target ethernet setting uses the broadcast +ethernet address to send packets, which can cause increased load on +other systems on the same ethernet segment. + +NOTE: the network device (eth1 in the above case) can run any kind +of other network traffic, netconsole is not intrusive. Netconsole +might cause slight delays in other traffic if the volume of kernel +messages is high, but should have no other impact. + +Netconsole was designed to be as instantaneous as possible, to +enable the logging of even the most critical kernel bugs. It works +from IRQ contexts as well, and does not enable interrupts while +sending packets. Due to these unique needs, configuration can not +be more automatic, and some fundamental limitations will remain: +only IP networks, UDP packets and ethernet devices are supported. diff -Nru a/arch/cris/arch-v10/drivers/ethernet.c b/arch/cris/arch-v10/drivers/ethernet.c --- a/arch/cris/arch-v10/drivers/ethernet.c Thu Jan 22 18:59:25 2004 +++ b/arch/cris/arch-v10/drivers/ethernet.c Thu Jan 22 18:59:25 2004 @@ -482,7 +482,7 @@ /* Register device */ err = register_netdev(dev); if (err) { - kfree(dev); + free_netdev(dev); return err; } diff -Nru a/arch/ia64/hp/sim/simeth.c b/arch/ia64/hp/sim/simeth.c --- a/arch/ia64/hp/sim/simeth.c Thu Jan 22 18:59:25 2004 +++ b/arch/ia64/hp/sim/simeth.c Thu Jan 22 18:59:25 2004 @@ -224,7 +224,7 @@ err = register_netdev(dev); if (err) { - kfree(dev); + free_netdev(dev); return err; } diff -Nru a/arch/ppc/8260_io/enet.c b/arch/ppc/8260_io/enet.c --- a/arch/ppc/8260_io/enet.c Thu Jan 22 18:59:23 2004 +++ b/arch/ppc/8260_io/enet.c Thu Jan 22 18:59:23 2004 @@ -851,7 +851,7 @@ err = register_netdev(dev); if (err) { - kfree(dev); + free_netdev(dev); return err; } diff -Nru a/arch/ppc/8260_io/fcc_enet.c b/arch/ppc/8260_io/fcc_enet.c --- a/arch/ppc/8260_io/fcc_enet.c Thu Jan 22 18:59:25 2004 +++ b/arch/ppc/8260_io/fcc_enet.c Thu Jan 22 18:59:25 2004 @@ -1371,7 +1371,7 @@ err = register_netdev(dev); if (err) { - kfree(dev); + free_netdev(dev); return err; } diff -Nru a/arch/ppc/8xx_io/enet.c b/arch/ppc/8xx_io/enet.c --- a/arch/ppc/8xx_io/enet.c Thu Jan 22 18:59:24 2004 +++ b/arch/ppc/8xx_io/enet.c Thu Jan 22 18:59:24 2004 @@ -949,7 +949,7 @@ err = register_netdev(dev); if (err) { - kfree(dev); + free_netdev(dev); return err; } diff -Nru a/arch/ppc/8xx_io/fec.c b/arch/ppc/8xx_io/fec.c --- a/arch/ppc/8xx_io/fec.c Thu Jan 22 18:59:26 2004 +++ b/arch/ppc/8xx_io/fec.c Thu Jan 22 18:59:26 2004 @@ -1748,7 +1748,7 @@ err = register_netdev(dev); if (err) { - kfree(dev); + free_netdev(dev); return err; } diff -Nru a/arch/um/drivers/net_kern.c b/arch/um/drivers/net_kern.c --- a/arch/um/drivers/net_kern.c Thu Jan 22 18:59:25 2004 +++ b/arch/um/drivers/net_kern.c Thu Jan 22 18:59:25 2004 @@ -358,8 +358,12 @@ rtnl_lock(); err = register_netdevice(dev); rtnl_unlock(); - if (err) + if (err) { + device->dev = NULL; + /* XXX: should we call ->remove() here? */ + free_netdev(dev); return 1; + } lp = dev->priv; INIT_LIST_HEAD(&lp->list); diff -Nru a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c --- a/drivers/char/pcmcia/synclink_cs.c Thu Jan 22 18:59:24 2004 +++ b/drivers/char/pcmcia/synclink_cs.c Thu Jan 22 18:59:24 2004 @@ -244,7 +244,6 @@ char netname[10]; struct net_device *netdev; struct net_device_stats netstats; - struct net_device netdevice; #endif } MGSLPC_INFO; @@ -4206,35 +4205,46 @@ #ifdef CONFIG_SYNCLINK_SYNCPPP /* syncppp net device routines */ + +static void mgslpc_setup(struct net_device *dev) +{ + dev->open = mgslpc_sppp_open; + dev->stop = mgslpc_sppp_close; + dev->hard_start_xmit = mgslpc_sppp_tx; + dev->do_ioctl = mgslpc_sppp_ioctl; + dev->get_stats = mgslpc_net_stats; + dev->tx_timeout = mgslpc_sppp_tx_timeout; + dev->watchdog_timeo = 10*HZ; +} void mgslpc_sppp_init(MGSLPC_INFO *info) { struct net_device *d; sprintf(info->netname,"mgslp%d",info->line); + + d = alloc_netdev(0, info->netname, mgslpc_setup); + if (!d) { + printk(KERN_WARNING "%s: alloc_netdev failed.\n", + info->netname); + return; + } info->if_ptr = &info->pppdev; - info->netdev = info->pppdev.dev = &info->netdevice; + info->netdev = info->pppdev.dev = d; sppp_attach(&info->pppdev); - d = info->netdev; - strcpy(d->name,info->netname); d->base_addr = info->io_base; d->irq = info->irq_level; d->priv = info; - d->init = NULL; - d->open = mgslpc_sppp_open; - d->stop = mgslpc_sppp_close; - d->hard_start_xmit = mgslpc_sppp_tx; - d->do_ioctl = mgslpc_sppp_ioctl; - d->get_stats = mgslpc_net_stats; - d->tx_timeout = mgslpc_sppp_tx_timeout; - d->watchdog_timeo = 10*HZ; if (register_netdev(d)) { printk(KERN_WARNING "%s: register_netdev failed.\n", d->name); sppp_detach(info->netdev); + info->netdev = NULL; + info->pppdev.dev = NULL; + free_netdev(d); return; } @@ -4246,8 +4256,11 @@ { if (debug_level >= DEBUG_LEVEL_INFO) printk("mgslpc_sppp_delete(%s)\n",info->netname); - sppp_detach(info->netdev); unregister_netdev(info->netdev); + sppp_detach(info->netdev); + free_netdev(info->netdev); + info->netdev = NULL; + info->pppdev.dev = NULL; } int mgslpc_sppp_open(struct net_device *d) diff -Nru a/drivers/char/synclink.c b/drivers/char/synclink.c --- a/drivers/char/synclink.c Thu Jan 22 18:59:24 2004 +++ b/drivers/char/synclink.c Thu Jan 22 18:59:24 2004 @@ -327,7 +327,6 @@ char netname[10]; struct net_device *netdev; struct net_device_stats netstats; - struct net_device netdevice; #endif }; @@ -737,8 +736,8 @@ #ifdef CONFIG_SYNCLINK_SYNCPPP /* SPPP/HDLC stuff */ -void mgsl_sppp_init(struct mgsl_struct *info); -void mgsl_sppp_delete(struct mgsl_struct *info); +static void mgsl_sppp_init(struct mgsl_struct *info); +static void mgsl_sppp_delete(struct mgsl_struct *info); int mgsl_sppp_open(struct net_device *d); int mgsl_sppp_close(struct net_device *d); void mgsl_sppp_tx_timeout(struct net_device *d); @@ -7820,36 +7819,45 @@ #ifdef CONFIG_SYNCLINK_SYNCPPP /* syncppp net device routines */ +static void mgsl_setup(struct net_device *dev) +{ + dev->open = mgsl_sppp_open; + dev->stop = mgsl_sppp_close; + dev->hard_start_xmit = mgsl_sppp_tx; + dev->do_ioctl = mgsl_sppp_ioctl; + dev->get_stats = mgsl_net_stats; + dev->tx_timeout = mgsl_sppp_tx_timeout; + dev->watchdog_timeo = 10*HZ; +} -void mgsl_sppp_init(struct mgsl_struct *info) +static void mgsl_sppp_init(struct mgsl_struct *info) { struct net_device *d; sprintf(info->netname,"mgsl%d",info->line); + d = alloc_netdev(0, info->netname, mgsl_setup); + if (!d) { + printk(KERN_WARNING "%s: alloc_netdev failed.\n", + info->netname); + return; + } + info->if_ptr = &info->pppdev; - info->netdev = info->pppdev.dev = &info->netdevice; + info->netdev = info->pppdev.dev = d; sppp_attach(&info->pppdev); - d = info->netdev; - strcpy(d->name,info->netname); d->base_addr = info->io_base; d->irq = info->irq_level; d->dma = info->dma_level; d->priv = info; - d->init = NULL; - d->open = mgsl_sppp_open; - d->stop = mgsl_sppp_close; - d->hard_start_xmit = mgsl_sppp_tx; - d->do_ioctl = mgsl_sppp_ioctl; - d->get_stats = mgsl_net_stats; - d->tx_timeout = mgsl_sppp_tx_timeout; - d->watchdog_timeo = 10*HZ; if (register_netdev(d)) { printk(KERN_WARNING "%s: register_netdev failed.\n", d->name); sppp_detach(info->netdev); + info->netdev = NULL; + free_netdev(d); return; } @@ -7861,8 +7869,11 @@ { if (debug_level >= DEBUG_LEVEL_INFO) printk("mgsl_sppp_delete(%s)\n",info->netname); - sppp_detach(info->netdev); unregister_netdev(info->netdev); + sppp_detach(info->netdev); + free_netdev(info->netdev); + info->netdev = NULL; + info->pppdev.dev = NULL; } int mgsl_sppp_open(struct net_device *d) diff -Nru a/drivers/char/synclinkmp.c b/drivers/char/synclinkmp.c --- a/drivers/char/synclinkmp.c Thu Jan 22 18:59:24 2004 +++ b/drivers/char/synclinkmp.c Thu Jan 22 18:59:24 2004 @@ -289,7 +289,6 @@ char netname[10]; struct net_device *netdev; struct net_device_stats netstats; - struct net_device netdevice; #endif } SLMP_INFO; @@ -1627,35 +1626,44 @@ /* syncppp support and callbacks */ +static void cb_setup(struct net_device *dev) +{ + dev->open = sppp_cb_open; + dev->stop = sppp_cb_close; + dev->hard_start_xmit = sppp_cb_tx; + dev->do_ioctl = sppp_cb_ioctl; + dev->get_stats = sppp_cb_net_stats; + dev->tx_timeout = sppp_cb_tx_timeout; + dev->watchdog_timeo = 10*HZ; +} + static void sppp_init(SLMP_INFO *info) { struct net_device *d; sprintf(info->netname,"mgslm%dp%d",info->adapter_num,info->port_num); + d = alloc_netdev(0, info->netname, cb_setup); + if (!d) { + printk(KERN_WARNING "%s: alloc_netdev failed.\n", + info->netname); + return; + } + info->if_ptr = &info->pppdev; - info->netdev = info->pppdev.dev = &info->netdevice; + info->netdev = info->pppdev.dev = d; sppp_attach(&info->pppdev); - d = info->netdev; - strcpy(d->name,info->netname); - d->base_addr = 0; d->irq = info->irq_level; - d->dma = 0; d->priv = info; - d->init = NULL; - d->open = sppp_cb_open; - d->stop = sppp_cb_close; - d->hard_start_xmit = sppp_cb_tx; - d->do_ioctl = sppp_cb_ioctl; - d->get_stats = sppp_cb_net_stats; - d->tx_timeout = sppp_cb_tx_timeout; - d->watchdog_timeo = 10*HZ; if (register_netdev(d)) { printk(KERN_WARNING "%s: register_netdev failed.\n", d->name); sppp_detach(info->netdev); + info->netdev = NULL; + info->pppdev.dev = NULL; + free_netdev(d); return; } @@ -1667,8 +1675,11 @@ { if (debug_level >= DEBUG_LEVEL_INFO) printk("sppp_delete(%s)\n",info->netname); - sppp_detach(info->netdev); unregister_netdev(info->netdev); + sppp_detach(info->netdev); + free_netdev(info->netdev); + info->netdev = NULL; + info->pppdev.dev = NULL; } static int sppp_cb_open(struct net_device *d) diff -Nru a/drivers/ieee1394/eth1394.c b/drivers/ieee1394/eth1394.c --- a/drivers/ieee1394/eth1394.c Thu Jan 22 18:59:25 2004 +++ b/drivers/ieee1394/eth1394.c Thu Jan 22 18:59:25 2004 @@ -395,8 +395,8 @@ } } -/* This function is called by register_netdev */ -static int ether1394_init_dev (struct net_device *dev) +/* This function is called right before register_netdev */ +static void ether1394_init_dev (struct net_device *dev) { /* Our functions */ dev->open = ether1394_open; @@ -423,8 +423,6 @@ dev->type = ARPHRD_IEEE1394; ether1394_reset_priv (dev, 1); - - return 0; } /* @@ -461,8 +459,6 @@ SET_MODULE_OWNER(dev); - dev->init = ether1394_init_dev; - priv = (struct eth1394_priv *)dev->priv; spin_lock_init(&priv->lock); @@ -483,6 +479,8 @@ goto out; } + ether1394_init_dev(dev); + if (register_netdev (dev)) { ETH1394_PRINT (KERN_ERR, dev->name, "Error registering network driver\n"); goto out; @@ -507,7 +505,7 @@ out: if (dev != NULL) - kfree(dev); + free_netdev(dev); if (hi) hpsb_destroy_hostinfo(ð1394_highlevel, host); diff -Nru a/drivers/isdn/i4l/isdn_ppp.c b/drivers/isdn/i4l/isdn_ppp.c --- a/drivers/isdn/i4l/isdn_ppp.c Thu Jan 22 18:59:26 2004 +++ b/drivers/isdn/i4l/isdn_ppp.c Thu Jan 22 18:59:26 2004 @@ -1125,12 +1125,15 @@ return -EINVAL; switch (cmd) { + +#define PPP_VERSION "2.3.7" case SIOCGPPPVER: r = (char *) ifr->ifr_ifru.ifru_data; len = strlen(PPP_VERSION) + 1; if (copy_to_user(r, PPP_VERSION, len)) error = -EFAULT; break; + case SIOCGPPPSTATS: error = isdn_ppp_dev_ioctl_stats(ifr, dev); break; diff -Nru a/drivers/media/dvb/dvb-core/dvb_net.c b/drivers/media/dvb/dvb-core/dvb_net.c --- a/drivers/media/dvb/dvb-core/dvb_net.c Thu Jan 22 18:59:24 2004 +++ b/drivers/media/dvb/dvb-core/dvb_net.c Thu Jan 22 18:59:24 2004 @@ -523,7 +523,8 @@ net->base_addr = pid; if ((result = register_netdev(net)) < 0) { - kfree(net); + dvbnet->device[if_num] = NULL; + free_netdev(net); return result; } @@ -545,6 +546,7 @@ flush_scheduled_work(); unregister_netdev(net); dvbnet->state[num]=0; + dvbnet->device[num] = NULL; free_netdev(net); return 0; diff -Nru a/drivers/message/fusion/mptlan.c b/drivers/message/fusion/mptlan.c --- a/drivers/message/fusion/mptlan.c Thu Jan 22 18:59:25 2004 +++ b/drivers/message/fusion/mptlan.c Thu Jan 22 18:59:25 2004 @@ -1437,7 +1437,7 @@ SET_MODULE_OWNER(dev); if (register_netdev(dev) != 0) { - kfree(dev); + free_netdev(dev); dev = NULL; } return dev; diff -Nru a/drivers/net/3c501.c b/drivers/net/3c501.c --- a/drivers/net/3c501.c Thu Jan 22 18:59:23 2004 +++ b/drivers/net/3c501.c Thu Jan 22 18:59:23 2004 @@ -136,17 +136,14 @@ #include "3c501.h" -/* A zero-terminated list of I/O addresses to be probed. - The 3c501 can be at many locations, but here are the popular ones. */ -static unsigned int netcard_portlist[] __initdata = { - 0x280, 0x300, 0 -}; - - /* * The boilerplate probe code. */ +static int io=0x280; +static int irq=5; +static int mem_start; + /** * el1_probe: - probe for a 3c501 * @dev: The device structure passed in to probe. @@ -160,23 +157,47 @@ * probe and failing to find anything. */ -int __init el1_probe(struct net_device *dev) +struct net_device * __init el1_probe(int unit) { - int i; - int base_addr = dev->base_addr; + struct net_device *dev = alloc_etherdev(sizeof(struct net_local)); + static unsigned ports[] = { 0x280, 0x300, 0}; + unsigned *port; + int err = 0; + + if (!dev) + return ERR_PTR(-ENOMEM); + + if (unit >= 0) { + sprintf(dev->name, "eth%d", unit); + netdev_boot_setup_check(dev); + io = dev->base_addr; + irq = dev->irq; + mem_start = dev->mem_start & 7; + } SET_MODULE_OWNER(dev); - if (base_addr > 0x1ff) /* Check a single specified location. */ - return el1_probe1(dev, base_addr); - else if (base_addr != 0) /* Don't probe at all. */ - return -ENXIO; - - for (i = 0; netcard_portlist[i]; i++) - if (el1_probe1(dev, netcard_portlist[i]) == 0) - return 0; - - return -ENODEV; + if (io > 0x1ff) { /* Check a single specified location. */ + err = el1_probe1(dev, io); + } else if (io != 0) { + err = -ENXIO; /* Don't probe at all. */ + } else { + for (port = ports; *port && el1_probe1(dev, *port); port++) + ; + if (!*port) + err = -ENODEV; + } + if (err) + goto out; + err = register_netdev(dev); + if (err) + goto out1; + return dev; +out1: + release_region(dev->base_addr, EL1_IO_EXTENT); +out: + free_netdev(dev); + return ERR_PTR(err); } /** @@ -240,6 +261,8 @@ * high. */ + dev->irq = irq; + if (dev->irq < 2) { unsigned long irq_mask; @@ -267,8 +290,8 @@ dev->base_addr = ioaddr; memcpy(dev->dev_addr, station_addr, ETH_ALEN); - if (dev->mem_start & 0xf) - el_debug = dev->mem_start & 0x7; + if (mem_start & 0xf) + el_debug = mem_start & 0x7; if (autoirq) dev->irq = autoirq; @@ -282,17 +305,7 @@ if (el_debug) printk(KERN_DEBUG "%s", version); - /* - * Initialize the device structure. - */ - - dev->priv = kmalloc(sizeof(struct net_local), GFP_KERNEL); - if (dev->priv == NULL) { - release_region(ioaddr, EL1_IO_EXTENT); - return -ENOMEM; - } memset(dev->priv, 0, sizeof(struct net_local)); - lp=dev->priv; spin_lock_init(&lp->lock); @@ -308,13 +321,6 @@ dev->get_stats = &el1_get_stats; dev->set_multicast_list = &set_multicast_list; dev->ethtool_ops = &netdev_ethtool_ops; - - /* - * Setup the generic properties - */ - - ether_setup(dev); - return 0; } @@ -884,14 +890,8 @@ #ifdef MODULE -static struct net_device dev_3c501 = { - .init = el1_probe, - .base_addr = 0x280, - .irq = 5, -}; +static struct net_device *dev_3c501; -static int io=0x280; -static int irq=5; MODULE_PARM(io, "i"); MODULE_PARM(irq, "i"); MODULE_PARM_DESC(io, "EtherLink I/O base address"); @@ -911,10 +911,9 @@ int init_module(void) { - dev_3c501.irq=irq; - dev_3c501.base_addr=io; - if (register_netdev(&dev_3c501) != 0) - return -EIO; + dev_3c501 = el1_probe(-1); + if (IS_ERR(dev_3c501)) + return PTR_ERR(dev_3c501); return 0; } @@ -927,19 +926,10 @@ void cleanup_module(void) { - unregister_netdev(&dev_3c501); - - /* - * Free up the private structure, or leak memory :-) - */ - - kfree(dev_3c501.priv); - dev_3c501.priv = NULL; /* gets re-allocated by el1_probe1 */ - - /* - * If we don't do this, we can't re-insmod it later. - */ - release_region(dev_3c501.base_addr, EL1_IO_EXTENT); + struct net_device *dev = dev_3c501; + unregister_netdev(dev); + release_region(dev->base_addr, EL1_IO_EXTENT); + free_netdev(dev); } #endif /* MODULE */ diff -Nru a/drivers/net/3c501.h b/drivers/net/3c501.h --- a/drivers/net/3c501.h Thu Jan 22 18:59:24 2004 +++ b/drivers/net/3c501.h Thu Jan 22 18:59:24 2004 @@ -3,7 +3,6 @@ * Index to functions. */ -int el1_probe(struct net_device *dev); static int el1_probe1(struct net_device *dev, int ioaddr); static int el_open(struct net_device *dev); static void el_timeout(struct net_device *dev); diff -Nru a/drivers/net/3c503.c b/drivers/net/3c503.c --- a/drivers/net/3c503.c Thu Jan 22 18:59:26 2004 +++ b/drivers/net/3c503.c Thu Jan 22 18:59:26 2004 @@ -60,7 +60,6 @@ #include "3c503.h" #define WRD_COUNT 4 -int el2_probe(struct net_device *dev); static int el2_pio_probe(struct net_device *dev); static int el2_probe1(struct net_device *dev, int ioaddr); @@ -90,11 +89,11 @@ If the ethercard isn't found there is an optional probe for ethercard jumpered to programmed-I/O mode. */ -int __init -el2_probe(struct net_device *dev) +static int __init do_el2_probe(struct net_device *dev) { int *addr, addrs[] = { 0xddffe, 0xd9ffe, 0xcdffe, 0xc9ffe, 0}; int base_addr = dev->base_addr; + int irq = dev->irq; SET_MODULE_OWNER(dev); @@ -104,16 +103,13 @@ return -ENXIO; for (addr = addrs; *addr; addr++) { - int i; - unsigned int base_bits = isa_readb(*addr); - /* Find first set bit. */ - for(i = 7; i >= 0; i--, base_bits >>= 1) - if (base_bits & 0x1) - break; - if (base_bits != 1) + unsigned base_bits = isa_readb(*addr); + int i = ffs(base_bits) - 1; + if (i == -1 || base_bits != (1 << i)) continue; if (el2_probe1(dev, netcard_portlist[i]) == 0) return 0; + dev->irq = irq; } #if ! defined(no_probe_nonshared_memory) return el2_pio_probe(dev); @@ -128,20 +124,54 @@ el2_pio_probe(struct net_device *dev) { int i; - int base_addr = dev ? dev->base_addr : 0; + int base_addr = dev->base_addr; + int irq = dev->irq; if (base_addr > 0x1ff) /* Check a single specified location. */ return el2_probe1(dev, base_addr); else if (base_addr != 0) /* Don't probe at all. */ return -ENXIO; - for (i = 0; netcard_portlist[i]; i++) + for (i = 0; netcard_portlist[i]; i++) { if (el2_probe1(dev, netcard_portlist[i]) == 0) return 0; + dev->irq = irq; + } return -ENODEV; } +static void cleanup_card(struct net_device *dev) +{ + /* NB: el2_close() handles free_irq */ + release_region(dev->base_addr, EL2_IO_EXTENT); +} + +struct net_device * __init el2_probe(int unit) +{ + struct net_device *dev = alloc_ei_netdev(); + int err; + + if (!dev) + return ERR_PTR(-ENOMEM); + + sprintf(dev->name, "eth%d", unit); + netdev_boot_setup_check(dev); + + err = do_el2_probe(dev); + if (err) + goto out; + err = register_netdev(dev); + if (err) + goto out1; + return dev; +out1: + cleanup_card(dev); +out: + free_netdev(dev); + return ERR_PTR(err); +} + /* Probe for the Etherlink II card at I/O port base IOADDR, returning non-zero on success. If found, set the station address and memory parameters in DEVICE. */ @@ -152,15 +182,19 @@ static unsigned version_printed; unsigned long vendor_id; - /* FIXME: code reads ioaddr + 0x400, we request ioaddr + 16 */ if (!request_region(ioaddr, EL2_IO_EXTENT, dev->name)) return -EBUSY; + if (!request_region(ioaddr + 0x400, 8, dev->name)) { + retval = -EBUSY; + goto out; + } + /* Reset and/or avoid any lurking NE2000 */ if (inb(ioaddr + 0x408) == 0xff) { mdelay(1); retval = -ENODEV; - goto out; + goto out1; } /* We verify that it's a 3C503 board by checking the first three octets @@ -171,7 +205,7 @@ if ( (iobase_reg & (iobase_reg - 1)) || (membase_reg & (membase_reg - 1))) { retval = -ENODEV; - goto out; + goto out1; } saved_406 = inb_p(ioaddr + 0x406); outb_p(ECNTRL_RESET|ECNTRL_THIN, ioaddr + 0x406); /* Reset it... */ @@ -184,19 +218,13 @@ /* Restore the register we frobbed. */ outb(saved_406, ioaddr + 0x406); retval = -ENODEV; - goto out; + goto out1; } if (ei_debug && version_printed++ == 0) printk(version); dev->base_addr = ioaddr; - /* Allocate dev->priv and fill in 8390 specific dev fields. */ - if (ethdev_init(dev)) { - printk ("3c503: unable to allocate memory for dev->priv.\n"); - retval = -ENOMEM; - goto out; - } printk("%s: 3c503 at i/o base %#3x, node ", dev->name, ioaddr); @@ -309,6 +337,9 @@ dev->open = &el2_open; dev->stop = &el2_close; dev->ethtool_ops = &netdev_ethtool_ops; +#ifdef CONFIG_NET_POLL_CONTROLLER + dev->poll_controller = ei_poll; +#endif if (dev->mem_start) printk("%s: %s - %dkB RAM, 8kB shared mem window at %#6lx-%#6lx.\n", @@ -322,7 +353,10 @@ printk("\n%s: %s, %dkB RAM, using programmed I/O (REJUMPER for SHARED MEMORY).\n", dev->name, ei_status.name, (wordlength+1)<<3); } + release_region(ioaddr + 0x400, 8); return 0; +out1: + release_region(ioaddr + 0x400, 8); out: release_region(ioaddr, EL2_IO_EXTENT); return retval; @@ -633,7 +667,7 @@ #ifdef MODULE #define MAX_EL2_CARDS 4 /* Max number of EL2 cards per module */ -static struct net_device dev_el2[MAX_EL2_CARDS]; +static struct net_device *dev_el2[MAX_EL2_CARDS]; static int io[MAX_EL2_CARDS]; static int irq[MAX_EL2_CARDS]; static int xcvr[MAX_EL2_CARDS]; /* choose int. or ext. xcvr */ @@ -651,28 +685,34 @@ int init_module(void) { + struct net_device *dev; int this_dev, found = 0; for (this_dev = 0; this_dev < MAX_EL2_CARDS; this_dev++) { - struct net_device *dev = &dev_el2[this_dev]; - dev->irq = irq[this_dev]; - dev->base_addr = io[this_dev]; - dev->mem_end = xcvr[this_dev]; /* low 4bits = xcvr sel. */ - dev->init = el2_probe; if (io[this_dev] == 0) { if (this_dev != 0) break; /* only autoprobe 1st one */ printk(KERN_NOTICE "3c503.c: Presently autoprobing (not recommended) for a single card.\n"); } - if (register_netdev(dev) != 0) { - printk(KERN_WARNING "3c503.c: No 3c503 card found (i/o = 0x%x).\n", io[this_dev]); - if (found != 0) { /* Got at least one. */ - return 0; + dev = alloc_ei_netdev(); + if (!dev) + break; + dev->irq = irq[this_dev]; + dev->base_addr = io[this_dev]; + dev->mem_end = xcvr[this_dev]; /* low 4bits = xcvr sel. */ + if (do_el2_probe(dev) == 0) { + if (register_netdev(dev) == 0) { + dev_el2[found++] = dev; + continue; } - return -ENXIO; + cleanup_card(dev); } - found++; + free_netdev(dev); + printk(KERN_WARNING "3c503.c: No 3c503 card found (i/o = 0x%x).\n", io[this_dev]); + break; } - return 0; + if (found) + return 0; + return -ENXIO; } void @@ -681,13 +721,11 @@ int this_dev; for (this_dev = 0; this_dev < MAX_EL2_CARDS; this_dev++) { - struct net_device *dev = &dev_el2[this_dev]; - if (dev->priv != NULL) { - void *priv = dev->priv; - /* NB: el2_close() handles free_irq */ - release_region(dev->base_addr, EL2_IO_EXTENT); + struct net_device *dev = dev_el2[this_dev]; + if (dev) { unregister_netdev(dev); - kfree(priv); + cleanup_card(dev); + free_netdev(dev); } } } diff -Nru a/drivers/net/3c505.c b/drivers/net/3c505.c --- a/drivers/net/3c505.c Thu Jan 22 18:59:27 2004 +++ b/drivers/net/3c505.c Thu Jan 22 18:59:27 2004 @@ -1293,42 +1293,6 @@ } } -/****************************************************** - * - * initialise Etherlink Plus board - * - ******************************************************/ - -static inline void elp_init(struct net_device *dev) -{ - elp_device *adapter = dev->priv; - - /* - * set ptrs to various functions - */ - dev->open = elp_open; /* local */ - dev->stop = elp_close; /* local */ - dev->get_stats = elp_get_stats; /* local */ - dev->hard_start_xmit = elp_start_xmit; /* local */ - dev->tx_timeout = elp_timeout; /* local */ - dev->watchdog_timeo = 10*HZ; - dev->set_multicast_list = elp_set_mc_list; /* local */ - dev->ethtool_ops = &netdev_ethtool_ops; /* local */ - - /* Setup the generic properties */ - ether_setup(dev); - - /* - * setup ptr to adapter specific information - */ - memset(&(adapter->stats), 0, sizeof(struct net_device_stats)); - - /* - * memory information - */ - dev->mem_start = dev->mem_end = 0; -} - /************************************************************ * * A couple of tests to see if there's 3C505 or not @@ -1442,12 +1406,13 @@ * work at all if it was in a weird state). */ -int __init elplus_probe(struct net_device *dev) +static int __init elplus_setup(struct net_device *dev) { - elp_device *adapter; + elp_device *adapter = dev->priv; int i, tries, tries1, okay; unsigned long timeout; unsigned long cookie = 0; + int err = -ENODEV; SET_MODULE_OWNER(dev); @@ -1456,17 +1421,8 @@ */ dev->base_addr = elp_autodetect(dev); - if (!(dev->base_addr)) - return -ENODEV; - - /* - * setup ptr to adapter specific information - */ - adapter = (elp_device *) (dev->priv = kmalloc(sizeof(elp_device), GFP_KERNEL)); - if (adapter == NULL) { - printk(KERN_ERR "%s: out of memory\n", dev->name); + if (!dev->base_addr) return -ENODEV; - } adapter->send_pcb_semaphore = 0; @@ -1544,8 +1500,7 @@ outb_control(adapter->hcr_val & ~(FLSH | ATTN), dev); } printk(KERN_ERR "%s: failed to initialise 3c505\n", dev->name); - release_region(dev->base_addr, ELP_IO_EXTENT); - return -ENODEV; + goto out; okay: if (dev->irq) { /* Is there a preset IRQ? */ @@ -1560,14 +1515,14 @@ case 0: printk(KERN_ERR "%s: IRQ probe failed: check 3c505 jumpers.\n", dev->name); - return -ENODEV; + goto out; case 1: case 6: case 8: case 13: printk(KERN_ERR "%s: Impossible IRQ %d reported by probe_irq_off().\n", dev->name, dev->irq); - return -ENODEV; + goto out; } /* * Now we have the IRQ number so we can disable the interrupts from @@ -1636,16 +1591,48 @@ printk(KERN_ERR "%s: adapter configuration failed\n", dev->name); } - /* - * initialise the device - */ - elp_init(dev); + dev->open = elp_open; /* local */ + dev->stop = elp_close; /* local */ + dev->get_stats = elp_get_stats; /* local */ + dev->hard_start_xmit = elp_start_xmit; /* local */ + dev->tx_timeout = elp_timeout; /* local */ + dev->watchdog_timeo = 10*HZ; + dev->set_multicast_list = elp_set_mc_list; /* local */ + dev->ethtool_ops = &netdev_ethtool_ops; /* local */ + + memset(&(adapter->stats), 0, sizeof(struct net_device_stats)); + dev->mem_start = dev->mem_end = 0; + + err = register_netdev(dev); + if (err) + goto out; return 0; +out: + release_region(dev->base_addr, ELP_IO_EXTENT); + return err; +} + +struct net_device * __init elplus_probe(int unit) +{ + struct net_device *dev = alloc_etherdev(sizeof(elp_device)); + int err; + if (!dev) + return ERR_PTR(-ENOMEM); + + sprintf(dev->name, "eth%d", unit); + netdev_boot_setup_check(dev); + + err = elplus_setup(dev); + if (err) { + free_netdev(dev); + return ERR_PTR(err); + } + return dev; } #ifdef MODULE -static struct net_device dev_3c505[ELP_MAX_CARDS]; +static struct net_device *dev_3c505[ELP_MAX_CARDS]; static int io[ELP_MAX_CARDS]; static int irq[ELP_MAX_CARDS]; static int dma[ELP_MAX_CARDS]; @@ -1661,10 +1648,12 @@ int this_dev, found = 0; for (this_dev = 0; this_dev < ELP_MAX_CARDS; this_dev++) { - struct net_device *dev = &dev_3c505[this_dev]; + struct net_device *dev = alloc_etherdev(sizeof(elp_device)); + if (!dev) + break; + dev->irq = irq[this_dev]; dev->base_addr = io[this_dev]; - dev->init = elplus_probe; if (dma[this_dev]) { dev->dma = dma[this_dev]; } else { @@ -1672,16 +1661,22 @@ printk(KERN_WARNING "3c505.c: warning, using default DMA channel,\n"); } if (io[this_dev] == 0) { - if (this_dev) break; + if (this_dev) { + free_netdev(dev); + break; + } printk(KERN_NOTICE "3c505.c: module autoprobe not recommended, give io=xx.\n"); } - if (register_netdev(dev) != 0) { + if (elplus_setup(dev) != 0) { printk(KERN_WARNING "3c505.c: Failed to register card at 0x%x.\n", io[this_dev]); - if (found != 0) return 0; - return -ENXIO; + free_netdev(dev); + break; } + dev_3c505[this_dev] = dev; found++; } + if (!found) + return -ENODEV; return 0; } @@ -1690,12 +1685,11 @@ int this_dev; for (this_dev = 0; this_dev < ELP_MAX_CARDS; this_dev++) { - struct net_device *dev = &dev_3c505[this_dev]; - if (dev->priv != NULL) { + struct net_device *dev = dev_3c505[this_dev]; + if (dev) { unregister_netdev(dev); - kfree(dev->priv); - dev->priv = NULL; release_region(dev->base_addr, ELP_IO_EXTENT); + free_netdev(dev); } } } diff -Nru a/drivers/net/3c507.c b/drivers/net/3c507.c --- a/drivers/net/3c507.c Thu Jan 22 18:59:26 2004 +++ b/drivers/net/3c507.c Thu Jan 22 18:59:26 2004 @@ -74,10 +74,6 @@ #define debug net_debug -/* A zero-terminated list of common I/O addresses to be probed. */ -static unsigned int netcard_portlist[] __initdata = - { 0x300, 0x320, 0x340, 0x280, 0}; - /* Details of the i82586. @@ -286,8 +282,6 @@ /* Index to functions, as function prototypes. */ -extern int el16_probe(struct net_device *dev); /* Called from Space.c */ - static int el16_probe1(struct net_device *dev, int ioaddr); static int el16_open(struct net_device *dev); static int el16_send_packet(struct sk_buff *skb, struct net_device *dev); @@ -301,6 +295,10 @@ static void init_82586_mem(struct net_device *dev); static struct ethtool_ops netdev_ethtool_ops; +static int io = 0x300; +static int irq; +static int mem_start; + /* Check for a network adaptor of this type, and return '0' iff one exists. If dev->base_addr == 0, probe all likely locations. @@ -309,23 +307,50 @@ device and return success. */ -int __init el16_probe(struct net_device *dev) +struct net_device * __init el16_probe(int unit) { - int base_addr = dev->base_addr; - int i; + struct net_device *dev = alloc_etherdev(sizeof(struct net_local)); + static unsigned ports[] = { 0x300, 0x320, 0x340, 0x280, 0}; + unsigned *port; + int err = -ENODEV; + + if (!dev) + return ERR_PTR(-ENODEV); + + if (unit >= 0) { + sprintf(dev->name, "eth%d", unit); + netdev_boot_setup_check(dev); + io = dev->base_addr; + irq = dev->irq; + mem_start = dev->mem_start & 15; + } SET_MODULE_OWNER(dev); - if (base_addr > 0x1ff) /* Check a single specified location. */ - return el16_probe1(dev, base_addr); - else if (base_addr != 0) - return -ENXIO; /* Don't probe at all. */ - - for (i = 0; netcard_portlist[i]; i++) - if (el16_probe1(dev, netcard_portlist[i]) == 0) - return 0; + if (io > 0x1ff) /* Check a single specified location. */ + err = el16_probe1(dev, io); + else if (io != 0) + err = -ENXIO; /* Don't probe at all. */ + else { + for (port = ports; *port; port++) { + err = el16_probe1(dev, *port); + if (!err) + break; + } + } - return -ENODEV; + if (err) + goto out; + err = register_netdev(dev); + if (err) + goto out1; + return dev; +out1: + free_irq(dev->irq, dev); + release_region(dev->base_addr, EL16_IO_EXTENT); +out: + free_netdev(dev); + return ERR_PTR(err); } static int __init el16_probe1(struct net_device *dev, int ioaddr) @@ -383,8 +408,8 @@ printk(" %02x", dev->dev_addr[i]); } - if ((dev->mem_start & 0xf) > 0) - net_debug = dev->mem_start & 7; + if (mem_start) + net_debug = mem_start & 7; #ifdef MEM_BASE dev->mem_start = MEM_BASE; @@ -416,27 +441,18 @@ if (net_debug) printk(version); - /* Initialize the device structure. */ - lp = dev->priv = kmalloc(sizeof(struct net_local), GFP_KERNEL); - if (dev->priv == NULL) { - retval = -ENOMEM; - goto out; - } - memset(dev->priv, 0, sizeof(struct net_local)); + lp = dev->priv; + memset(lp, 0, sizeof(*lp)); spin_lock_init(&lp->lock); - dev->open = el16_open; - dev->stop = el16_close; + dev->open = el16_open; + dev->stop = el16_close; dev->hard_start_xmit = el16_send_packet; dev->get_stats = el16_get_stats; dev->tx_timeout = el16_tx_timeout; dev->watchdog_timeo = TX_TIMEOUT; dev->ethtool_ops = &netdev_ethtool_ops; - - ether_setup(dev); /* Generic ethernet behaviour */ - - dev->flags&=~IFF_MULTICAST; /* Multicast doesn't work */ - + dev->flags &= ~IFF_MULTICAST; /* Multicast doesn't work */ return 0; out: release_region(ioaddr, EL16_IO_EXTENT); @@ -899,9 +915,7 @@ }; #ifdef MODULE -static struct net_device dev_3c507; -static int io = 0x300; -static int irq; +static struct net_device *dev_3c507; MODULE_PARM(io, "i"); MODULE_PARM(irq, "i"); MODULE_PARM_DESC(io, "EtherLink16 I/O base address"); @@ -911,26 +925,18 @@ { if (io == 0) printk("3c507: You should not use auto-probing with insmod!\n"); - dev_3c507.base_addr = io; - dev_3c507.irq = irq; - dev_3c507.init = el16_probe; - if (register_netdev(&dev_3c507) != 0) { - printk("3c507: register_netdev() returned non-zero.\n"); - return -EIO; - } - return 0; + dev_3c507 = el16_probe(-1); + return IS_ERR(dev_3c507) ? PTR_ERR(dev_3c507) : 0; } void cleanup_module(void) { - unregister_netdev(&dev_3c507); - kfree(dev_3c507.priv); - dev_3c507.priv = NULL; - - /* If we don't do this, we can't re-insmod it later. */ - free_irq(dev_3c507.irq, &dev_3c507); - release_region(dev_3c507.base_addr, EL16_IO_EXTENT); + struct net_device *dev = dev_3c507; + unregister_netdev(dev); + free_irq(dev->irq, dev); + release_region(dev->base_addr, EL16_IO_EXTENT); + free_netdev(dev); } #endif /* MODULE */ MODULE_LICENSE("GPL"); diff -Nru a/drivers/net/3c509.c b/drivers/net/3c509.c --- a/drivers/net/3c509.c Thu Jan 22 18:59:23 2004 +++ b/drivers/net/3c509.c Thu Jan 22 18:59:23 2004 @@ -678,6 +678,8 @@ err = el3_common_init(dev); if (err) { + device->driver_data = NULL; + free_netdev(dev); return -ENOMEM; } @@ -737,6 +739,8 @@ err = el3_common_init(dev); if (err) { + eisa_set_drvdata (edev, NULL); + free_netdev(dev); return err; } diff -Nru a/drivers/net/3c515.c b/drivers/net/3c515.c --- a/drivers/net/3c515.c Thu Jan 22 18:59:24 2004 +++ b/drivers/net/3c515.c Thu Jan 22 18:59:24 2004 @@ -307,7 +307,8 @@ struct corkscrew_private { const char *product_name; - struct net_device *next_module; + struct list_head list; + struct net_device *our_dev; /* The Rx and Tx rings are here to keep them quad-word-aligned. */ struct boom_rx_desc rx_ring[RX_RING_SIZE]; struct boom_tx_desc tx_ring[TX_RING_SIZE]; @@ -329,6 +330,7 @@ full_bus_master_tx:1, full_bus_master_rx:1, /* Boomerang */ tx_full:1; spinlock_t lock; + struct device *dev; }; /* The action to take with a media selection timer tick. @@ -367,17 +369,12 @@ MODULE_DEVICE_TABLE(isapnp, corkscrew_isapnp_adapters); -static int corkscrew_isapnp_phys_addr[3]; - static int nopnp; #endif /* __ISAPNP__ */ -static int corkscrew_scan(struct net_device *dev); -static struct net_device *corkscrew_found_device(struct net_device *dev, - int ioaddr, int irq, - int product_index, - int options); -static int corkscrew_probe1(struct net_device *dev); +static struct net_device *corkscrew_scan(int unit); +static void corkscrew_setup(struct net_device *dev, int ioaddr, + struct pnp_dev *idev, int card_number); static int corkscrew_open(struct net_device *dev); static void corkscrew_timer(unsigned long arg); static int corkscrew_start_xmit(struct sk_buff *skb, @@ -413,47 +410,99 @@ #ifdef MODULE static int debug = -1; /* A list of all installed Vortex devices, for removing the driver module. */ -static struct net_device *root_corkscrew_dev; +/* we will need locking (and refcounting) if we ever use it for more */ +static LIST_HEAD(root_corkscrew_dev); int init_module(void) { - int cards_found; - + int found = 0; if (debug >= 0) corkscrew_debug = debug; if (corkscrew_debug) printk(version); - - root_corkscrew_dev = NULL; - cards_found = corkscrew_scan(NULL); - return cards_found ? 0 : -ENODEV; + while (corkscrew_scan(-1)) + found++; + return found ? 0 : -ENODEV; } #else -int tc515_probe(struct net_device *dev) +struct net_device *tc515_probe(int unit) { - int cards_found = 0; + struct net_device *dev = corkscrew_scan(unit); + static int printed; - SET_MODULE_OWNER(dev); - - cards_found = corkscrew_scan(dev); + if (!dev) + return ERR_PTR(-ENODEV); - if (corkscrew_debug > 0 && cards_found) + if (corkscrew_debug > 0 && !printed) { + printed = 1; printk(version); + } - return cards_found ? 0 : -ENODEV; + return dev; } #endif /* not MODULE */ -static int corkscrew_scan(struct net_device *dev) +static int check_device(unsigned ioaddr) +{ + int timer; + + if (!request_region(ioaddr, CORKSCREW_TOTAL_SIZE, "3c515")) + return 0; + /* Check the resource configuration for a matching ioaddr. */ + if ((inw(ioaddr + 0x2002) & 0x1f0) != (ioaddr & 0x1f0)) { + release_region(ioaddr, CORKSCREW_TOTAL_SIZE); + return 0; + } + /* Verify by reading the device ID from the EEPROM. */ + outw(EEPROM_Read + 7, ioaddr + Wn0EepromCmd); + /* Pause for at least 162 us. for the read to take place. */ + for (timer = 4; timer >= 0; timer--) { + udelay(162); + if ((inw(ioaddr + Wn0EepromCmd) & 0x0200) == 0) + break; + } + if (inw(ioaddr + Wn0EepromData) != 0x6d50) { + release_region(ioaddr, CORKSCREW_TOTAL_SIZE); + return 0; + } + return 1; +} + +static void cleanup_card(struct net_device *dev) +{ + struct corkscrew_private *vp = (struct corkscrew_private *) dev->priv; + list_del_init(&vp->list); + if (dev->dma) + free_dma(dev->dma); + outw(TotalReset, dev->base_addr + EL3_CMD); + release_region(dev->base_addr, CORKSCREW_TOTAL_SIZE); + if (vp->dev) + pnp_device_detach(to_pnp_dev(vp->dev)); +} + +static struct net_device *corkscrew_scan(int unit) { - int cards_found = 0; + struct net_device *dev; + static int cards_found = 0; static int ioaddr; + int err; #ifdef __ISAPNP__ short i; static int pnp_cards; #endif + dev = alloc_etherdev(sizeof(struct corkscrew_private)); + if (!dev) + return ERR_PTR(-ENOMEM); + + if (unit >= 0) { + sprintf(dev->name, "eth%d", unit); + netdev_boot_setup_check(dev); + } + + SET_MODULE_OWNER(dev); + #ifdef __ISAPNP__ if(nopnp == 1) goto no_pnp; @@ -470,7 +519,7 @@ if (pnp_activate_dev(idev) < 0) { printk("pnp activate failed (out of resources?)\n"); pnp_device_detach(idev); - return -ENOMEM; + continue; } if (!pnp_port_valid(idev, 0) || !pnp_irq_valid(idev, 0)) { pnp_device_detach(idev); @@ -478,40 +527,22 @@ } ioaddr = pnp_port_start(idev, 0); irq = pnp_irq(idev, 0); - if(corkscrew_debug) - printk ("ISAPNP reports %s at i/o 0x%x, irq %d\n", - (char*) corkscrew_isapnp_adapters[i].driver_data, ioaddr, irq); - - if ((inw(ioaddr + 0x2002) & 0x1f0) != (ioaddr & 0x1f0)) { + if (!check_device(ioaddr)) { pnp_device_detach(idev); continue; } - /* Verify by reading the device ID from the EEPROM. */ - { - int timer; - outw(EEPROM_Read + 7, ioaddr + Wn0EepromCmd); - /* Pause for at least 162 us. for the read to take place. */ - for (timer = 4; timer >= 0; timer--) { - udelay(162); - if ((inw(ioaddr + Wn0EepromCmd) & 0x0200) - == 0) - break; - } - if (inw(ioaddr + Wn0EepromData) != 0x6d50) { - pnp_device_detach(idev); - continue; - } - } + if(corkscrew_debug) + printk ("ISAPNP reports %s at i/o 0x%x, irq %d\n", + (char*) corkscrew_isapnp_adapters[i].driver_data, ioaddr, irq); printk(KERN_INFO "3c515 Resource configuration register %#4.4x, DCR %4.4x.\n", inl(ioaddr + 0x2002), inw(ioaddr + 0x2000)); /* irq = inw(ioaddr + 0x2002) & 15; */ /* Use the irq from isapnp */ - corkscrew_isapnp_phys_addr[pnp_cards] = ioaddr; - corkscrew_found_device(dev, ioaddr, irq, CORKSCREW_ID, dev - && dev->mem_start ? dev-> - mem_start : options[cards_found]); - dev = 0; + corkscrew_setup(dev, ioaddr, idev, cards_found++); pnp_cards++; - cards_found++; + err = register_netdev(dev); + if (!err) + return dev; + cleanup_card(dev); } } no_pnp: @@ -519,122 +550,64 @@ /* Check all locations on the ISA bus -- evil! */ for (ioaddr = 0x100; ioaddr < 0x400; ioaddr += 0x20) { - int irq; -#ifdef __ISAPNP__ - /* Make sure this was not already picked up by isapnp */ - if(ioaddr == corkscrew_isapnp_phys_addr[0]) continue; - if(ioaddr == corkscrew_isapnp_phys_addr[1]) continue; - if(ioaddr == corkscrew_isapnp_phys_addr[2]) continue; -#endif /* __ISAPNP__ */ - if (check_region(ioaddr, CORKSCREW_TOTAL_SIZE)) - continue; - /* Check the resource configuration for a matching ioaddr. */ - if ((inw(ioaddr + 0x2002) & 0x1f0) != (ioaddr & 0x1f0)) + if (!check_device(ioaddr)) continue; - /* Verify by reading the device ID from the EEPROM. */ - { - int timer; - outw(EEPROM_Read + 7, ioaddr + Wn0EepromCmd); - /* Pause for at least 162 us. for the read to take place. */ - for (timer = 4; timer >= 0; timer--) { - udelay(162); - if ((inw(ioaddr + Wn0EepromCmd) & 0x0200) - == 0) - break; - } - if (inw(ioaddr + Wn0EepromData) != 0x6d50) - continue; - } + printk(KERN_INFO "3c515 Resource configuration register %#4.4x, DCR %4.4x.\n", inl(ioaddr + 0x2002), inw(ioaddr + 0x2000)); - irq = inw(ioaddr + 0x2002) & 15; - corkscrew_found_device(dev, ioaddr, irq, CORKSCREW_ID, - dev && dev->mem_start ? dev->mem_start : - (cards_found >= MAX_UNITS ? -1 : - options[cards_found])); - dev = 0; - cards_found++; + corkscrew_setup(dev, ioaddr, NULL, cards_found++); + err = register_netdev(dev); + if (!err) + return dev; + cleanup_card(dev); } - if (corkscrew_debug) - printk(KERN_INFO "%d 3c515 cards found.\n", cards_found); - return cards_found; + free_netdev(dev); + return NULL; } -static struct net_device *corkscrew_found_device(struct net_device *dev, - int ioaddr, int irq, - int product_index, - int options) +static void corkscrew_setup(struct net_device *dev, int ioaddr, + struct pnp_dev *idev, int card_number) { - struct corkscrew_private *vp; - -#ifdef MODULE - /* Allocate and fill new device structure. */ - int dev_size = sizeof(struct net_device) + sizeof(struct corkscrew_private) + 15; /* Pad for alignment */ + struct corkscrew_private *vp = (struct corkscrew_private *) dev->priv; + unsigned int eeprom[0x40], checksum = 0; /* EEPROM contents */ + int i; + int irq; - dev = (struct net_device *) kmalloc(dev_size, GFP_KERNEL); - if (!dev) - return NULL; - memset(dev, 0, dev_size); - /* Align the Rx and Tx ring entries. */ - dev->priv = (void *) (((long) dev + sizeof(struct net_device) + 15) & ~15); - vp = (struct corkscrew_private *) dev->priv; - dev->base_addr = ioaddr; - dev->irq = irq; - dev->dma = (product_index == CORKSCREW_ID ? inw(ioaddr + 0x2000) & 7 : 0); - dev->init = corkscrew_probe1; - vp->product_name = "3c515"; - vp->options = options; - if (options >= 0) { - vp->media_override = ((options & 7) == 2) ? 0 : options & 7; - vp->full_duplex = (options & 8) ? 1 : 0; - vp->bus_master = (options & 16) ? 1 : 0; + if (idev) { + irq = pnp_irq(idev, 0); + vp->dev = &idev->dev; } else { - vp->media_override = 7; - vp->full_duplex = 0; - vp->bus_master = 0; + irq = inw(ioaddr + 0x2002) & 15; } - ether_setup(dev); - vp->next_module = root_corkscrew_dev; - root_corkscrew_dev = dev; - SET_MODULE_OWNER(dev); - if (register_netdev(dev) != 0) { - kfree(dev); - return NULL; - } -#else /* not a MODULE */ - /* Caution: quad-word alignment required for rings! */ - dev->priv = kmalloc(sizeof(struct corkscrew_private), GFP_KERNEL); - if (!dev->priv) - return NULL; - memset(dev->priv, 0, sizeof(struct corkscrew_private)); - dev = init_etherdev(dev, sizeof(struct corkscrew_private)); + dev->base_addr = ioaddr; dev->irq = irq; - dev->dma = (product_index == CORKSCREW_ID ? inw(ioaddr + 0x2000) & 7 : 0); - vp = (struct corkscrew_private *) dev->priv; + dev->dma = inw(ioaddr + 0x2000) & 7; vp->product_name = "3c515"; - vp->options = options; - if (options >= 0) { - vp->media_override = ((options & 7) == 2) ? 0 : options & 7; - vp->full_duplex = (options & 8) ? 1 : 0; - vp->bus_master = (options & 16) ? 1 : 0; + vp->options = dev->mem_start; + vp->our_dev = dev; + + if (!vp->options) { + if (card_number >= MAX_UNITS) + vp->options = -1; + else + vp->options = options[card_number]; + } + + if (vp->options >= 0) { + vp->media_override = vp->options & 7; + if (vp->media_override == 2) + vp->media_override = 0; + vp->full_duplex = (vp->options & 8) ? 1 : 0; + vp->bus_master = (vp->options & 16) ? 1 : 0; } else { vp->media_override = 7; vp->full_duplex = 0; vp->bus_master = 0; } - - corkscrew_probe1(dev); -#endif /* MODULE */ - return dev; -} - -static int corkscrew_probe1(struct net_device *dev) -{ - int ioaddr = dev->base_addr; - struct corkscrew_private *vp = (struct corkscrew_private *) dev->priv; - unsigned int eeprom[0x40], checksum = 0; /* EEPROM contents */ - int i; +#ifdef MODULE + list_add(&vp->list, &root_corkscrew_dev); +#endif printk(KERN_INFO "%s: 3Com %s at %#3x,", dev->name, vp->product_name, ioaddr); @@ -706,9 +679,6 @@ /* vp->full_bus_master_rx = 0; */ vp->full_bus_master_rx = (vp->capabilities & 0x20) ? 1 : 0; - /* We do a request_region() to register /proc/ioports info. */ - request_region(ioaddr, CORKSCREW_TOTAL_SIZE, vp->product_name); - /* The 3c51x-specific entries in the device structure. */ dev->open = &corkscrew_open; dev->hard_start_xmit = &corkscrew_start_xmit; @@ -718,8 +688,6 @@ dev->get_stats = &corkscrew_get_stats; dev->set_multicast_list = &set_rx_mode; dev->ethtool_ops = &netdev_ethtool_ops; - - return 0; } @@ -1607,20 +1575,16 @@ #ifdef MODULE void cleanup_module(void) { - struct net_device *next_dev; - - while (root_corkscrew_dev) { - next_dev = - ((struct corkscrew_private *) root_corkscrew_dev-> - priv)->next_module; - if (root_corkscrew_dev->dma) - free_dma(root_corkscrew_dev->dma); - unregister_netdev(root_corkscrew_dev); - outw(TotalReset, root_corkscrew_dev->base_addr + EL3_CMD); - release_region(root_corkscrew_dev->base_addr, - CORKSCREW_TOTAL_SIZE); - free_netdev(root_corkscrew_dev); - root_corkscrew_dev = next_dev; + while (!list_empty(&root_corkscrew_dev)) { + struct net_device *dev; + struct corkscrew_private *vp; + + vp = list_entry(root_corkscrew_dev.next, + struct corkscrew_private, list); + dev = vp->our_dev; + unregister_netdev(dev); + cleanup_card(dev); + free_netdev(dev); } } #endif /* MODULE */ diff -Nru a/drivers/net/3c523.c b/drivers/net/3c523.c --- a/drivers/net/3c523.c Thu Jan 22 18:59:25 2004 +++ b/drivers/net/3c523.c Thu Jan 22 18:59:25 2004 @@ -410,7 +410,7 @@ /*****************************************************************/ -int __init elmc_probe(struct net_device *dev) +static int __init do_elmc_probe(struct net_device *dev) { static int slot; int base_addr = dev->base_addr; @@ -420,7 +420,7 @@ int i = 0; unsigned int size = 0; int retval; - struct priv *pr; + struct priv *pr = dev->priv; SET_MODULE_OWNER(dev); if (MCA_bus == 0) { @@ -455,10 +455,9 @@ } /* we didn't find any 3c523 in the slots we checked for */ - if (slot == MCA_NOTFOUND) { - retval = ((base_addr || irq) ? -ENXIO : -ENODEV); - goto err_out; - } + if (slot == MCA_NOTFOUND) + return ((base_addr || irq) ? -ENXIO : -ENODEV); + mca_set_adapter_name(slot, "3Com 3c523 Etherlink/MC"); mca_set_adapter_procfn(slot, (MCA_ProcFn) elmc_getinfo, dev); @@ -497,13 +496,7 @@ break; } - pr = dev->priv = kmalloc(sizeof(struct priv), GFP_KERNEL); - if (dev->priv == NULL) { - retval = -ENOMEM; - goto err_out; - } memset(pr, 0, sizeof(struct priv)); - pr->slot = slot; printk(KERN_INFO "%s: 3Com 3c523 Rev 0x%x at %#lx\n", dev->name, (int) revision, @@ -530,8 +523,6 @@ if (!check586(dev, dev->mem_start, size)) { printk(KERN_ERR "%s: memprobe, Can't find memory at 0x%lx!\n", dev->name, dev->mem_start); - kfree(dev->priv); - dev->priv = NULL; retval = -ENODEV; goto err_out; } @@ -573,8 +564,6 @@ #endif dev->ethtool_ops = &netdev_ethtool_ops; - ether_setup(dev); - /* note that we haven't actually requested the IRQ from the kernel. That gets done in elmc_open(). I'm not sure that's such a good idea, but it works, so I'll go with it. */ @@ -585,9 +574,41 @@ return 0; err_out: + mca_set_adapter_procfn(slot, NULL, NULL); release_region(dev->base_addr, ELMC_IO_EXTENT); return retval; } + +static void cleanup_card(struct net_device *dev) +{ + mca_set_adapter_procfn(((struct priv *) (dev->priv))->slot, NULL, NULL); + release_region(dev->base_addr, ELMC_IO_EXTENT); +} + +struct net_device * __init elmc_probe(int unit) +{ + struct net_device *dev = alloc_etherdev(sizeof(struct priv)); + int err; + + if (!dev) + return ERR_PTR(-ENOMEM); + + sprintf(dev->name, "eth%d", unit); + netdev_boot_setup_check(dev); + + err = do_elmc_probe(dev); + if (err) + goto out; + err = register_netdev(dev); + if (err) + goto out1; + return dev; +out1: + cleanup_card(dev); +out: + free_netdev(dev); + return ERR_PTR(err); +} /********************************************** * init the chip (elmc-interrupt should be disabled?!) @@ -1245,7 +1266,7 @@ /* Increase if needed ;) */ #define MAX_3C523_CARDS 4 -static struct net_device dev_elmc[MAX_3C523_CARDS]; +static struct net_device *dev_elmc[MAX_3C523_CARDS]; static int irq[MAX_3C523_CARDS]; static int io[MAX_3C523_CARDS]; MODULE_PARM(irq, "1-" __MODULE_STRING(MAX_3C523_CARDS) "i"); @@ -1258,16 +1279,24 @@ int this_dev,found = 0; /* Loop until we either can't find any more cards, or we have MAX_3C523_CARDS */ - for(this_dev=0; this_devirq=irq[this_dev]; dev->base_addr=io[this_dev]; - dev->init=elmc_probe; - if(register_netdev(dev)!=0) { - if(io[this_dev]==0) break; - printk(KERN_WARNING "3c523.c: No 3c523 card found at io=%#x\n",io[this_dev]); - } else found++; + if (do_elmc_probe(dev) == 0) { + if (register_netdev(dev) == 0) { + dev_elmc[this_dev] = dev; + found++; + continue; + } + cleanup_card(dev); + } + free_netdev(dev); + if (io[this_dev]==0) + break; + printk(KERN_WARNING "3c523.c: No 3c523 card found at io=%#x\n",io[this_dev]); } if(found==0) { @@ -1279,31 +1308,12 @@ void cleanup_module(void) { int this_dev; - for(this_dev=0; this_devpriv) { - /* shutdown interrupts on the card */ - elmc_id_reset586(); - if (dev->irq != 0) { - /* this should be done by close, but if we failed to - initialize properly something may have gotten hosed. */ - free_irq(dev->irq, dev); - dev->irq = 0; - } - if (dev->base_addr != 0) { - release_region(dev->base_addr, ELMC_IO_EXTENT); - dev->base_addr = 0; - } - irq[this_dev] = 0; - io[this_dev] = 0; + for (this_dev=0; this_devpriv))->slot, - NULL, NULL); - - kfree(dev->priv); - dev->priv = NULL; + cleanup_card(dev); + free_netdev(dev); } } } diff -Nru a/drivers/net/3c527.c b/drivers/net/3c527.c --- a/drivers/net/3c527.c Thu Jan 22 18:59:25 2004 +++ b/drivers/net/3c527.c Thu Jan 22 18:59:25 2004 @@ -212,8 +212,6 @@ /* Index to functions, as function prototypes. */ -extern int mc32_probe(struct net_device *dev); - static int mc32_probe1(struct net_device *dev, int ioaddr); static int mc32_command(struct net_device *dev, u16 cmd, void *data, int len); static int mc32_open(struct net_device *dev); @@ -226,9 +224,19 @@ static void mc32_reset_multicast_list(struct net_device *dev); static struct ethtool_ops netdev_ethtool_ops; +static void cleanup_card(struct net_device *dev) +{ + struct mc32_local *lp=dev->priv; + unsigned slot = lp->slot; + mca_mark_as_unused(slot); + mca_set_adapter_name(slot, NULL); + free_irq(dev->irq, dev); + release_region(dev->base_addr, MC32_IO_EXTENT); +} + /** * mc32_probe - Search for supported boards - * @dev: device to probe + * @unit: interface number to use * * Because MCA bus is a real bus and we can scan for cards we could do a * single scan for all boards here. Right now we use the passed in device @@ -236,10 +244,18 @@ * in particular. */ -int __init mc32_probe(struct net_device *dev) +struct net_device *__init mc32_probe(int unit) { + struct net_device *dev = alloc_etherdev(sizeof(struct mc32_local)); static int current_mca_slot = -1; int i; + int err; + + if (!dev) + return ERR_PTR(-ENOMEM); + + if (unit >= 0) + sprintf(dev->name, "eth%d", unit); SET_MODULE_OWNER(dev); @@ -260,12 +276,18 @@ mca_set_adapter_name(current_mca_slot, mc32_adapters[i].name); mca_mark_as_used(current_mca_slot); - return 0; + err = register_netdev(dev); + if (err) { + cleanup_card(dev); + free_netdev(dev); + dev = ERR_PTR(err); + } + return dev; } } } - return -ENODEV; + return ERR_PTR(-ENODEV); } /** @@ -285,7 +307,7 @@ int i, err; u8 POS; u32 base; - struct mc32_local *lp; + struct mc32_local *lp = dev->priv; static u16 mca_io_bases[]={ 0x7280,0x7290, 0x7680,0x7690, @@ -412,24 +434,14 @@ * Grab the IRQ */ - i = request_irq(dev->irq, &mc32_interrupt, SA_SHIRQ | SA_SAMPLE_RANDOM, dev->name, dev); - if (i) { + err = request_irq(dev->irq, &mc32_interrupt, SA_SHIRQ | SA_SAMPLE_RANDOM, dev->name, dev); + if (err) { release_region(dev->base_addr, MC32_IO_EXTENT); printk(KERN_ERR "%s: unable to get IRQ %d.\n", dev->name, dev->irq); - return i; - } - - - /* Initialize the device structure. */ - dev->priv = kmalloc(sizeof(struct mc32_local), GFP_KERNEL); - if (dev->priv == NULL) - { - err = -ENOMEM; - goto err_exit_irq; + goto err_exit_ports; } - memset(dev->priv, 0, sizeof(struct mc32_local)); - lp = dev->priv; + memset(lp, 0, sizeof(struct mc32_local)); lp->slot = slot; i=0; @@ -443,7 +455,7 @@ { printk(KERN_ERR "%s: failed to boot adapter.\n", dev->name); err = -ENODEV; - goto err_exit_free; + goto err_exit_irq; } udelay(1000); if(inb(dev->base_addr+2)&(1<<5)) @@ -458,7 +470,7 @@ else printk(KERN_ERR "%s: unknown failure %d.\n", dev->name, base); err = -ENODEV; - goto err_exit_free; + goto err_exit_irq; } base=0; @@ -474,7 +486,7 @@ { printk(KERN_ERR "%s: mailbox read fail (%d).\n", dev->name, i); err = -ENODEV; - goto err_exit_free; + goto err_exit_irq; } } @@ -517,15 +529,11 @@ dev->watchdog_timeo = HZ*5; /* Board does all the work */ dev->ethtool_ops = &netdev_ethtool_ops; - /* Fill in the fields of the device structure with ethernet values. */ - ether_setup(dev); - return 0; -err_exit_free: - kfree(dev->priv); err_exit_irq: free_irq(dev->irq, dev); +err_exit_ports: release_region(dev->base_addr, MC32_IO_EXTENT); return err; } @@ -1630,7 +1638,7 @@ #ifdef MODULE -static struct net_device this_device; +static struct net_device *this_device; /** * init_module - entry point @@ -1642,12 +1650,9 @@ int init_module(void) { - int result; - - this_device.init = mc32_probe; - if ((result = register_netdev(&this_device)) != 0) - return result; - + this_device = mc32_probe(-1); + if (IS_ERR(this_device)) + return PTR_ERR(this_device); return 0; } @@ -1664,24 +1669,9 @@ void cleanup_module(void) { - int slot; - - unregister_netdev(&this_device); - - /* - * If we don't do this, we can't re-insmod it later. - */ - - if (this_device.priv) - { - struct mc32_local *lp=this_device.priv; - slot = lp->slot; - mca_mark_as_unused(slot); - mca_set_adapter_name(slot, NULL); - kfree(this_device.priv); - } - free_irq(this_device.irq, &this_device); - release_region(this_device.base_addr, MC32_IO_EXTENT); + unregister_netdev(this_device); + cleanup_card(this_device); + free_netdev(this_device); } #endif /* MODULE */ diff -Nru a/drivers/net/3c59x.c b/drivers/net/3c59x.c --- a/drivers/net/3c59x.c Thu Jan 22 18:59:23 2004 +++ b/drivers/net/3c59x.c Thu Jan 22 18:59:23 2004 @@ -920,6 +920,18 @@ static int vortex_cards_found; +#ifdef CONFIG_NET_POLL_CONTROLLER +static void poll_vortex(struct net_device *dev) +{ + struct vortex_private *vp = (struct vortex_private *)dev->priv; + unsigned long flags; + local_save_flags(flags); + local_irq_disable(); + (vp->full_bus_master_rx ? boomerang_interrupt:vortex_interrupt)(dev->irq,dev,NULL); + local_irq_restore(flags); +} +#endif + #ifdef CONFIG_PM static int vortex_suspend (struct pci_dev *pdev, u32 state) @@ -1450,6 +1462,9 @@ dev->set_multicast_list = set_rx_mode; dev->tx_timeout = vortex_tx_timeout; dev->watchdog_timeo = (watchdog * HZ) / 1000; +#ifdef CONFIG_NET_POLL_CONTROLLER + dev->poll_controller = poll_vortex; +#endif if (pdev) { vp->pm_state_valid = 1; pci_save_state(VORTEX_PCI(vp), vp->power_state); diff -Nru a/drivers/net/8139too.c b/drivers/net/8139too.c --- a/drivers/net/8139too.c Thu Jan 22 18:59:23 2004 +++ b/drivers/net/8139too.c Thu Jan 22 18:59:23 2004 @@ -92,7 +92,7 @@ */ #define DRV_NAME "8139too" -#define DRV_VERSION "0.9.26" +#define DRV_VERSION "0.9.27" #include @@ -117,17 +117,17 @@ #define RTL8139_DRIVER_NAME DRV_NAME " Fast Ethernet driver " DRV_VERSION #define PFX DRV_NAME ": " +/* Default Message level */ +#define RTL8139_DEF_MSG_ENABLE (NETIF_MSG_DRV | \ + NETIF_MSG_PROBE | \ + NETIF_MSG_LINK) + /* enable PIO instead of MMIO, if CONFIG_8139TOO_PIO is selected */ #ifdef CONFIG_8139TOO_PIO #define USE_IO_OPS 1 #endif -/* use a 16K rx ring buffer instead of the default 32K */ -#ifdef CONFIG_SH_DREAMCAST -#define USE_BUF16K 1 -#endif - /* define to 1 to enable copious debugging info */ #undef RTL8139_DEBUG @@ -146,9 +146,9 @@ # define assert(expr) do {} while (0) #else # define assert(expr) \ - if(!(expr)) { \ - printk( "Assertion failed! %s,%s,%s,line=%d\n", \ - #expr,__FILE__,__FUNCTION__,__LINE__); \ + if(unlikely(!(expr))) { \ + printk(KERN_ERR "Assertion failed! %s,%s,%s,line=%d\n", \ + #expr,__FILE__,__FUNCTION__,__LINE__); \ } #endif @@ -159,9 +159,6 @@ static int media[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1}; static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1}; -/* Maximum events (Rx packets, etc.) to handle at each interrupt. */ -static int max_interrupt_work = 20; - /* Maximum number of multicast addresses to filter (vs. Rx-all-multicast). The RTL chips use a 64 element hash table based on the Ethernet CRC. */ static int multicast_filter_limit = 32; @@ -169,16 +166,16 @@ /* bitmapped message enable number */ static int debug = -1; -/* Size of the in-memory receive ring. */ -#ifdef USE_BUF16K -#define RX_BUF_LEN_IDX 1 /* 0==8K, 1==16K, 2==32K, 3==64K */ -#else -#define RX_BUF_LEN_IDX 2 /* 0==8K, 1==16K, 2==32K, 3==64K */ -#endif -#define RX_BUF_LEN (8192 << RX_BUF_LEN_IDX) +/* Ring size is now a config option */ +#define RX_BUF_LEN (8192 << CONFIG_8139_RXBUF_IDX) #define RX_BUF_PAD 16 #define RX_BUF_WRAP_PAD 2048 /* spare padding to handle lack of packet wrap */ + +#if RX_BUF_LEN == 65536 +#define RX_BUF_TOT_LEN RX_BUF_LEN +#else #define RX_BUF_TOT_LEN (RX_BUF_LEN + RX_BUF_PAD + RX_BUF_WRAP_PAD) +#endif /* Number of Tx descriptor registers. */ #define NUM_TX_DESC 4 @@ -251,6 +248,10 @@ {0x11db, 0x1234, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 }, {0x1432, 0x9130, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 }, {0x02ac, 0x1012, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 }, + {0x018a, 0x0106, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 }, + {0x126c, 0x1211, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 }, + {0x1743, 0x8139, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 }, + {0x021b, 0x8139, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 }, #ifdef CONFIG_SH_SECUREEDGE5410 /* Bogus 8139 silicon reports 8129 without external PROM :-( */ @@ -450,7 +451,7 @@ RxCfgRcv32K = (1 << 12), RxCfgRcv64K = (1 << 11) | (1 << 12), - /* Disable packet wrap at end of Rx buffer */ + /* Disable packet wrap at end of Rx buffer. (not possible with 64k) */ RxNoWrap = (1 << 7), }; @@ -560,6 +561,7 @@ int drv_flags; struct pci_dev *pci_dev; u32 pci_state[16]; + u32 msg_enable; struct net_device_stats stats; unsigned char *rx_ring; unsigned int cur_rx; /* Index into the Rx buffer of next Rx pkt. */ @@ -574,6 +576,7 @@ char twistie, twist_row, twist_col; /* Twister tune state. */ unsigned int default_port:4; /* Last dev->if_port value. */ spinlock_t lock; + spinlock_t rx_lock; chip_t chipset; pid_t thr_pid; wait_queue_head_t thr_wait; @@ -590,13 +593,11 @@ MODULE_LICENSE("GPL"); MODULE_PARM (multicast_filter_limit, "i"); -MODULE_PARM (max_interrupt_work, "i"); MODULE_PARM (media, "1-" __MODULE_STRING(MAX_UNITS) "i"); MODULE_PARM (full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i"); MODULE_PARM (debug, "i"); MODULE_PARM_DESC (debug, "8139too bitmapped message enable number"); MODULE_PARM_DESC (multicast_filter_limit, "8139too maximum number of filtered multicast addresses"); -MODULE_PARM_DESC (max_interrupt_work, "8139too maximum events handled per interrupt"); MODULE_PARM_DESC (media, "8139too: Bits 4+9: force full duplex, bit 5: 100Mbps"); MODULE_PARM_DESC (full_duplex, "8139too: Force full duplex for board(s) (1)"); @@ -610,6 +611,10 @@ static void rtl8139_init_ring (struct net_device *dev); static int rtl8139_start_xmit (struct sk_buff *skb, struct net_device *dev); +static int rtl8139_poll(struct net_device *dev, int *budget); +#ifdef CONFIG_NET_POLL_CONTROLLER +static void rtl8139_poll_controller(struct net_device *dev); +#endif static irqreturn_t rtl8139_interrupt (int irq, void *dev_instance, struct pt_regs *regs); static int rtl8139_close (struct net_device *dev); @@ -682,16 +687,32 @@ PCIErr | PCSTimeout | RxUnderrun | RxOverflow | RxFIFOOver | TxErr | TxOK | RxErr | RxOK; -#ifdef USE_BUF16K +static const u16 rtl8139_norx_intr_mask = + PCIErr | PCSTimeout | RxUnderrun | + TxErr | TxOK | RxErr ; + +#if CONFIG_8139_RXBUF_IDX == 0 +static const unsigned int rtl8139_rx_config = + RxCfgRcv8K | RxNoWrap | + (RX_FIFO_THRESH << RxCfgFIFOShift) | + (RX_DMA_BURST << RxCfgDMAShift); +#elif CONFIG_8139_RXBUF_IDX == 1 static const unsigned int rtl8139_rx_config = RxCfgRcv16K | RxNoWrap | (RX_FIFO_THRESH << RxCfgFIFOShift) | (RX_DMA_BURST << RxCfgDMAShift); -#else +#elif CONFIG_8139_RXBUF_IDX == 2 static const unsigned int rtl8139_rx_config = RxCfgRcv32K | RxNoWrap | (RX_FIFO_THRESH << RxCfgFIFOShift) | (RX_DMA_BURST << RxCfgDMAShift); +#elif CONFIG_8139_RXBUF_IDX == 3 +static const unsigned int rtl8139_rx_config = + RxCfgRcv64K | + (RX_FIFO_THRESH << RxCfgFIFOShift) | + (RX_DMA_BURST << RxCfgDMAShift); +#else +#error "Invalid configuration for 8139_RXBUF_IDX" #endif static const unsigned int rtl8139_tx_config = @@ -868,9 +889,7 @@ match: DPRINTK ("chipset id (%d) == index %d, '%s'\n", - tmp, - tp->chipset, - rtl_chip_info[tp->chipset].name); + version, i, rtl_chip_info[i].name); if (tp->chipset >= CH_8139B) { u8 new_tmp8 = tmp8 = RTL_R8 (Config1); @@ -964,6 +983,8 @@ /* The Rtl8139-specific entries in the device structure. */ dev->open = rtl8139_open; dev->hard_start_xmit = rtl8139_start_xmit; + dev->poll = rtl8139_poll; + dev->weight = 64; dev->stop = rtl8139_close; dev->get_stats = rtl8139_get_stats; dev->set_multicast_list = rtl8139_set_rx_mode; @@ -971,6 +992,9 @@ dev->ethtool_ops = &rtl8139_ethtool_ops; dev->tx_timeout = rtl8139_tx_timeout; dev->watchdog_timeo = TX_TIMEOUT; +#ifdef CONFIG_NET_POLL_CONTROLLER + dev->poll_controller = rtl8139_poll_controller; +#endif /* note: the hardware is not capable of sg/csum/highdma, however * through the use of skb_copy_and_csum_dev we enable these @@ -986,7 +1010,10 @@ /* note: tp->chipset set in rtl8139_init_board */ tp->drv_flags = board_info[ent->driver_data].hw_flags; tp->mmio_addr = ioaddr; + tp->msg_enable = + (debug < 0 ? RTL8139_DEF_MSG_ENABLE : ((1 << debug) - 1)); spin_lock_init (&tp->lock); + spin_lock_init (&tp->rx_lock); init_waitqueue_head (&tp->thr_wait); init_completion (&tp->thr_exited); tp->mii.dev = dev; @@ -1288,9 +1315,7 @@ { struct rtl8139_private *tp = dev->priv; int retval; -#ifdef RTL8139_DEBUG void *ioaddr = tp->mmio_addr; -#endif retval = request_irq (dev->irq, rtl8139_interrupt, SA_SHIRQ, dev->name, dev); if (retval) @@ -1319,8 +1344,10 @@ rtl8139_init_ring (dev); rtl8139_hw_start (dev); + netif_start_queue (dev); - DPRINTK ("%s: rtl8139_open() ioaddr %#lx IRQ %d" + if (netif_msg_ifup(tp)) + printk(KERN_DEBUG "%s: rtl8139_open() ioaddr %#lx IRQ %d" " GP Pins %2.2x %s-duplex.\n", dev->name, pci_resource_start (tp->pci_dev, 1), dev->irq, RTL_R8 (MediaStatus), @@ -1337,7 +1364,7 @@ struct rtl8139_private *tp = dev->priv; if (tp->phys[0] >= 0) { - mii_check_media(&tp->mii, 1, init_media); + mii_check_media(&tp->mii, netif_msg_link(tp), init_media); } } @@ -1407,8 +1434,6 @@ /* Enable all known interrupts by setting the interrupt mask. */ RTL_W16 (IntrMask, rtl8139_intr_mask); - - netif_start_queue (dev); } @@ -1631,7 +1656,7 @@ } } -static void rtl8139_tx_clear (struct rtl8139_private *tp) +static inline void rtl8139_tx_clear (struct rtl8139_private *tp) { tp->cur_tx = 0; tp->dirty_tx = 0; @@ -1661,6 +1686,7 @@ if (tmp8 & CmdTxEnb) RTL_W8 (ChipCmd, CmdRxEnb); + spin_lock(&tp->rx_lock); /* Disable interrupts by clearing the interrupt mask. */ RTL_W16 (IntrMask, 0x0000); @@ -1679,9 +1705,12 @@ spin_unlock_irqrestore (&tp->lock, flags); /* ...and finally, reset everything */ - rtl8139_hw_start (dev); - - netif_wake_queue (dev); + if (netif_running(dev)) { + rtl8139_hw_start (dev); + netif_wake_queue (dev); + } + spin_unlock(&tp->rx_lock); + } @@ -1695,6 +1724,7 @@ /* Calculate the next Tx descriptor entry. */ entry = tp->cur_tx % NUM_TX_DESC; + /* Note: the chip doesn't have auto-pad! */ if (likely(len < TX_BUF_SIZE)) { if (len < ETH_ZLEN) memset(tp->tx_buf[entry], 0, ETH_ZLEN); @@ -1706,7 +1736,6 @@ return 0; } - /* Note: the chip doesn't have auto-pad! */ spin_lock_irq(&tp->lock); RTL_W32_F (TxStatus0 + (entry * sizeof (u32)), tp->tx_flag | max(len, (unsigned int)ETH_ZLEN)); @@ -1720,8 +1749,9 @@ netif_stop_queue (dev); spin_unlock_irq(&tp->lock); - DPRINTK ("%s: Queued Tx packet size %u to slot %d.\n", - dev->name, len, entry); + if (netif_msg_tx_queued(tp)) + printk (KERN_DEBUG "%s: Queued Tx packet size %u to slot %d.\n", + dev->name, len, entry); return 0; } @@ -1751,8 +1781,9 @@ /* Note: TxCarrierLost is always asserted at 100mbps. */ if (txstatus & (TxOutOfWindow | TxAborted)) { /* There was an major error, log it. */ - DPRINTK ("%s: Transmit error, Tx status %8.8x.\n", - dev->name, txstatus); + if (netif_msg_tx_err(tp)) + printk(KERN_DEBUG "%s: Transmit error, Tx status %8.8x.\n", + dev->name, txstatus); tp->stats.tx_errors++; if (txstatus & TxAborted) { tp->stats.tx_aborted_errors++; @@ -1792,8 +1823,7 @@ if (tp->dirty_tx != dirty_tx) { tp->dirty_tx = dirty_tx; mb(); - if (netif_queue_stopped (dev)) - netif_wake_queue (dev); + netif_wake_queue (dev); } } @@ -1807,8 +1837,9 @@ int tmp_work; #endif - DPRINTK ("%s: Ethernet frame had errors, status %8.8x.\n", - dev->name, rx_status); + if (netif_msg_rx_err (tp)) + printk(KERN_DEBUG "%s: Ethernet frame had errors, status %8.8x.\n", + dev->name, rx_status); tp->stats.rx_errors++; if (!(rx_status & RxStatusOK)) { if (rx_status & RxTooLong) { @@ -1880,30 +1911,41 @@ #endif } -static void rtl8139_rx_interrupt (struct net_device *dev, - struct rtl8139_private *tp, void *ioaddr) -{ - unsigned char *rx_ring; - u16 cur_rx; - - assert (dev != NULL); - assert (tp != NULL); - assert (ioaddr != NULL); +#if CONFIG_8139_RXBUF_IDX == 3 +static __inline__ void wrap_copy(struct sk_buff *skb, const unsigned char *ring, + u32 offset, unsigned int size) +{ + u32 left = RX_BUF_LEN - offset; + + if (size > left) { + memcpy(skb->data, ring + offset, left); + memcpy(skb->data+left, ring, size - left); + } else + memcpy(skb->data, ring + offset, size); +} +#endif - rx_ring = tp->rx_ring; - cur_rx = tp->cur_rx; +static int rtl8139_rx(struct net_device *dev, struct rtl8139_private *tp, + int budget) +{ + void *ioaddr = tp->mmio_addr; + int received = 0; + unsigned char *rx_ring = tp->rx_ring; + unsigned int cur_rx = tp->cur_rx; DPRINTK ("%s: In rtl8139_rx(), current %4.4x BufAddr %4.4x," " free to %4.4x, Cmd %2.2x.\n", dev->name, cur_rx, RTL_R16 (RxBufAddr), RTL_R16 (RxBufPtr), RTL_R8 (ChipCmd)); - while ((RTL_R8 (ChipCmd) & RxBufEmpty) == 0) { - int ring_offset = cur_rx % RX_BUF_LEN; + while (netif_running(dev) && received < budget + && (RTL_R8 (ChipCmd) & RxBufEmpty) == 0) { + u32 ring_offset = cur_rx % RX_BUF_LEN; u32 rx_status; unsigned int rx_size; unsigned int pkt_size; struct sk_buff *skb; + u16 status; rmb(); @@ -1912,8 +1954,9 @@ rx_size = rx_status >> 16; pkt_size = rx_size - 4; - DPRINTK ("%s: rtl8139_rx() status %4.4x, size %4.4x," - " cur %4.4x.\n", dev->name, rx_status, + if (netif_msg_rx_status(tp)) + printk(KERN_DEBUG "%s: rtl8139_rx() status %4.4x, size %4.4x," + " cur %4.4x.\n", dev->name, rx_status, rx_size, cur_rx); #if RTL8139_DEBUG > 2 { @@ -1930,9 +1973,9 @@ * Theoretically, this should never happen * since EarlyRx is disabled. */ - if (rx_size == 0xfff0) { + if (unlikely(rx_size == 0xfff0)) { tp->xstats.early_rx++; - break; + goto done; } /* If Rx err or invalid rx_size/rx_status received @@ -1940,55 +1983,69 @@ * Rx process gets reset, so we abort any further * Rx processing. */ - if ((rx_size > (MAX_ETH_FRAME_SIZE+4)) || - (rx_size < 8) || - (!(rx_status & RxStatusOK))) { + if (unlikely((rx_size > (MAX_ETH_FRAME_SIZE+4)) || + (rx_size < 8) || + (!(rx_status & RxStatusOK)))) { rtl8139_rx_err (rx_status, dev, tp, ioaddr); - return; + return -1; } /* Malloc up new buffer, compatible with net-2e. */ /* Omit the four octet CRC from the length. */ - /* TODO: consider allocating skb's outside of - * interrupt context, both to speed interrupt processing, - * and also to reduce the chances of having to - * drop packets here under memory pressure. - */ - skb = dev_alloc_skb (pkt_size + 2); - if (skb) { + if (likely(skb)) { skb->dev = dev; skb_reserve (skb, 2); /* 16 byte align the IP fields. */ - +#if CONFIG_8139_RXBUF_IDX == 3 + wrap_copy(skb, rx_ring, ring_offset+4, pkt_size); +#else eth_copy_and_sum (skb, &rx_ring[ring_offset + 4], pkt_size, 0); +#endif skb_put (skb, pkt_size); skb->protocol = eth_type_trans (skb, dev); - netif_rx (skb); + dev->last_rx = jiffies; tp->stats.rx_bytes += pkt_size; tp->stats.rx_packets++; + + netif_receive_skb (skb); } else { - printk (KERN_WARNING - "%s: Memory squeeze, dropping packet.\n", - dev->name); + if (net_ratelimit()) + printk (KERN_WARNING + "%s: Memory squeeze, dropping packet.\n", + dev->name); tp->stats.rx_dropped++; } + received++; cur_rx = (cur_rx + rx_size + 4 + 3) & ~3; - RTL_W16 (RxBufPtr, cur_rx - 16); + RTL_W16 (RxBufPtr, (u16) (cur_rx - 16)); - if (RTL_R16 (IntrStatus) & RxAckBits) + /* Clear out errors and receive interrupts */ + status = RTL_R16 (IntrStatus) & RxAckBits; + if (likely(status != 0)) { + if (unlikely(status & (RxFIFOOver | RxOverflow))) { + tp->stats.rx_errors++; + if (status & RxFIFOOver) + tp->stats.rx_fifo_errors++; + } RTL_W16_F (IntrStatus, RxAckBits); + } } + done: + +#if RTL8139_DEBUG > 1 DPRINTK ("%s: Done rtl8139_rx(), current %4.4x BufAddr %4.4x," " free to %4.4x, Cmd %2.2x.\n", dev->name, cur_rx, RTL_R16 (RxBufAddr), RTL_R16 (RxBufPtr), RTL_R8 (ChipCmd)); +#endif tp->cur_rx = cur_rx; + return received; } @@ -2014,14 +2071,12 @@ status &= ~RxUnderrun; } - /* XXX along with rtl8139_rx_err, are we double-counting errors? */ - if (status & - (RxUnderrun | RxOverflow | RxErr | RxFIFOOver)) + if (status & (RxUnderrun | RxErr)) tp->stats.rx_errors++; if (status & PCSTimeout) tp->stats.rx_length_errors++; - if (status & (RxUnderrun | RxFIFOOver)) + if (status & RxUnderrun) tp->stats.rx_fifo_errors++; if (status & PCIErr) { u16 pci_cmd_status; @@ -2033,6 +2088,39 @@ } } +static int rtl8139_poll(struct net_device *dev, int *budget) +{ + struct rtl8139_private *tp = dev->priv; + void *ioaddr = tp->mmio_addr; + int orig_budget = min(*budget, dev->quota); + int done = 1; + + spin_lock(&tp->rx_lock); + if (likely(RTL_R16(IntrStatus) & RxAckBits)) { + int work_done; + + work_done = rtl8139_rx(dev, tp, orig_budget); + if (likely(work_done > 0)) { + *budget -= work_done; + dev->quota -= work_done; + done = (work_done < orig_budget); + } + } + + if (done) { + /* + * Order is important since data can get interrupted + * again when we think we are done. + */ + local_irq_disable(); + RTL_W16_F(IntrMask, rtl8139_intr_mask); + __netif_rx_complete(dev); + local_irq_enable(); + } + spin_unlock(&tp->rx_lock); + + return !done; +} /* The interrupt handler does all of the Rx thread work and cleans up after the Tx thread. */ @@ -2041,68 +2129,59 @@ { struct net_device *dev = (struct net_device *) dev_instance; struct rtl8139_private *tp = dev->priv; - int boguscnt = max_interrupt_work; void *ioaddr = tp->mmio_addr; - int ackstat, status; + u16 status, ackstat; int link_changed = 0; /* avoid bogus "uninit" warning */ int handled = 0; spin_lock (&tp->lock); + status = RTL_R16 (IntrStatus); - do { - status = RTL_R16 (IntrStatus); + /* shared irq? */ + if (unlikely((status & rtl8139_intr_mask) == 0)) + goto out; - /* h/w no longer present (hotplug?) or major error, bail */ - if (status == 0xFFFF) - break; + handled = 1; - if ((status & - (PCIErr | PCSTimeout | RxUnderrun | RxOverflow | - RxFIFOOver | TxErr | TxOK | RxErr | RxOK)) == 0) - break; + /* h/w no longer present (hotplug?) or major error, bail */ + if (unlikely(status == 0xFFFF)) + goto out; - handled = 1; + /* close possible race's with dev_close */ + if (unlikely(!netif_running(dev))) { + RTL_W16 (IntrMask, 0); + goto out; + } - /* Acknowledge all of the current interrupt sources ASAP, but - an first get an additional status bit from CSCR. */ - if (status & RxUnderrun) - link_changed = RTL_R16 (CSCR) & CSCR_LinkChangeBit; + /* Acknowledge all of the current interrupt sources ASAP, but + an first get an additional status bit from CSCR. */ + if (unlikely(status & RxUnderrun)) + link_changed = RTL_R16 (CSCR) & CSCR_LinkChangeBit; - /* The chip takes special action when we clear RxAckBits, - * so we clear them later in rtl8139_rx_interrupt - */ - ackstat = status & ~(RxAckBits | TxErr); + ackstat = status & ~(RxAckBits | TxErr); + if (ackstat) RTL_W16 (IntrStatus, ackstat); - DPRINTK ("%s: interrupt status=%#4.4x ackstat=%#4.4x new intstat=%#4.4x.\n", - dev->name, status, ackstat, RTL_R16 (IntrStatus)); - - if (netif_running (dev) && (status & RxAckBits)) - rtl8139_rx_interrupt (dev, tp, ioaddr); - - /* Check uncommon events with one test. */ - if (status & (PCIErr | PCSTimeout | RxUnderrun | RxOverflow | - RxFIFOOver | RxErr)) - rtl8139_weird_interrupt (dev, tp, ioaddr, - status, link_changed); - - if (netif_running (dev) && (status & (TxOK | TxErr))) { - rtl8139_tx_interrupt (dev, tp, ioaddr); - if (status & TxErr) - RTL_W16 (IntrStatus, TxErr); + /* Receive packets are processed by poll routine. + If not running start it now. */ + if (status & RxAckBits){ + if (netif_rx_schedule_prep(dev)) { + RTL_W16_F (IntrMask, rtl8139_norx_intr_mask); + __netif_rx_schedule (dev); } - - boguscnt--; - } while (boguscnt > 0); - - if (boguscnt <= 0) { - printk (KERN_WARNING "%s: Too much work at interrupt, " - "IntrStatus=0x%4.4x.\n", dev->name, status); - - /* Clear all interrupt sources. */ - RTL_W16 (IntrStatus, 0xffff); } + /* Check uncommon events with one test. */ + if (unlikely(status & (PCIErr | PCSTimeout | RxUnderrun | RxErr))) + rtl8139_weird_interrupt (dev, tp, ioaddr, + status, link_changed); + + if (status & (TxOK | TxErr)) { + rtl8139_tx_interrupt (dev, tp, ioaddr); + if (status & TxErr) + RTL_W16 (IntrStatus, TxErr); + } + out: spin_unlock (&tp->lock); DPRINTK ("%s: exiting interrupt, intr_status=%#4.4x.\n", @@ -2110,6 +2189,18 @@ return IRQ_RETVAL(handled); } +#ifdef CONFIG_NET_POLL_CONTROLLER +/* + * Polling receive - used by netconsole and other diagnostic tools + * to allow network i/o with interrupts disabled. + */ +static void rtl8139_poll_controller(struct net_device *dev) +{ + disable_irq(dev->irq); + rtl8139_interrupt(dev->irq, dev, NULL); + enable_irq(dev->irq); +} +#endif static int rtl8139_close (struct net_device *dev) { @@ -2130,8 +2221,9 @@ } wait_for_completion (&tp->thr_exited); } - - DPRINTK ("%s: Shutting down ethercard, status was 0x%4.4x.\n", + + if (netif_msg_ifdown(tp)) + printk(KERN_DEBUG "%s: Shutting down ethercard, status was 0x%4.4x.\n", dev->name, RTL_R16 (IntrStatus)); spin_lock_irqsave (&tp->lock, flags); @@ -2289,12 +2381,14 @@ static u32 rtl8139_get_msglevel(struct net_device *dev) { - return debug; + struct rtl8139_private *np = dev->priv; + return np->msg_enable; } static void rtl8139_set_msglevel(struct net_device *dev, u32 datum) { - debug = datum; + struct rtl8139_private *np = dev->priv; + np->msg_enable = datum; } /* TODO: we are too slack to do reg dumping for pio, for now */ diff -Nru a/drivers/net/82596.c b/drivers/net/82596.c --- a/drivers/net/82596.c Thu Jan 22 18:59:26 2004 +++ b/drivers/net/82596.c Thu Jan 22 18:59:26 2004 @@ -1129,21 +1129,40 @@ printk(" %02X%02X, %s\n", add[12], add[13], str); } -int __init i82596_probe(struct net_device *dev) +static int io = 0x300; +static int irq = 10; + +struct net_device * __init i82596_probe(int unit) { + struct net_device *dev; int i; struct i596_private *lp; char eth_addr[8]; static int probed; + int err; if (probed) - return -ENODEV; + return ERR_PTR(-ENODEV); probed++; + + dev = alloc_etherdev(0); + if (!dev) + return ERR_PTR(-ENOMEM); + + if (unit >= 0) { + sprintf(dev->name, "eth%d", unit); + netdev_boot_setup_check(dev); + } else { + dev->base_addr = io; + dev->irq = irq; + } + #ifdef ENABLE_MVME16x_NET if (MACH_IS_MVME16x) { if (mvme16x_config & MVME16x_CONFIG_NO_ETHERNET) { printk(KERN_NOTICE "Ethernet probe disabled - chip not present\n"); - return -ENODEV; + err = -ENODEV; + goto out; } memcpy(eth_addr, (void *) 0xfffc1f2c, 6); /* YUCK! Get addr from NOVRAM */ dev->base_addr = MVME_I596_BASE; @@ -1174,7 +1193,8 @@ if (!request_region(ioaddr, I596_TOTAL_SIZE, dev->name)) { printk(KERN_ERR "82596: IO address 0x%04x in use\n", ioaddr); - return -EBUSY; + err = -EBUSY; + goto out; } for (i = 0; i < 8; i++) { @@ -1190,8 +1210,8 @@ if ((checksum % 0x100) || (memcmp(eth_addr, "\x00\x00\x49", 3) != 0)) { - release_region(ioaddr, I596_TOTAL_SIZE); - return -ENODEV; + err = -ENODEV; + goto out1; } dev->base_addr = ioaddr; @@ -1200,13 +1220,10 @@ #endif dev->mem_start = (int)__get_free_pages(GFP_ATOMIC, 0); if (!dev->mem_start) { -#ifdef ENABLE_APRICOT - release_region(dev->base_addr, I596_TOTAL_SIZE); -#endif - return -ENOMEM; + err = -ENOMEM; + goto out1; } - ether_setup(dev); DEB(DEB_PROBE,printk(KERN_INFO "%s: 82596 at %#3lx,", dev->name, dev->base_addr)); for (i = 0; i < 6; i++) @@ -1244,7 +1261,26 @@ lp->scb.rfd = I596_NULL; lp->lock = SPIN_LOCK_UNLOCKED; - return 0; + err = register_netdev(dev); + if (err) + goto out2; + return dev; +out2: +#ifdef __mc68000__ + /* XXX This assumes default cache mode to be IOMAP_FULL_CACHING, + * XXX which may be invalid (CONFIG_060_WRITETHROUGH) + */ + kernel_set_cachemode((void *)(dev->mem_start), 4096, + IOMAP_FULL_CACHING); +#endif + free_page ((u32)(dev->mem_start)); +out1: +#ifdef ENABLE_APRICOT + release_region(dev->base_addr, I596_TOTAL_SIZE); +#endif +out: + free_netdev(dev); + return ERR_PTR(err); } static irqreturn_t i596_interrupt(int irq, void *dev_id, struct pt_regs *regs) @@ -1532,11 +1568,9 @@ } #ifdef MODULE -static struct net_device dev_82596 = { .init = i82596_probe }; +static struct net_device *dev_82596; #ifdef ENABLE_APRICOT -static int io = 0x300; -static int irq = 10; MODULE_PARM(irq, "i"); MODULE_PARM_DESC(irq, "Apricot IRQ number"); #endif @@ -1547,34 +1581,31 @@ int init_module(void) { -#ifdef ENABLE_APRICOT - dev_82596.base_addr = io; - dev_82596.irq = irq; -#endif if (debug >= 0) i596_debug = debug; - if (register_netdev(&dev_82596) != 0) - return -EIO; + dev_82596 = i82596_probe(-1); + if (IS_ERR(dev_82596)) + return PTR_ERR(dev_82596); return 0; } void cleanup_module(void) { - unregister_netdev(&dev_82596); + unregister_netdev(dev_82596); #ifdef __mc68000__ /* XXX This assumes default cache mode to be IOMAP_FULL_CACHING, * XXX which may be invalid (CONFIG_060_WRITETHROUGH) */ - kernel_set_cachemode((void *)(dev_82596.mem_start), 4096, + kernel_set_cachemode((void *)(dev_82596->mem_start), 4096, IOMAP_FULL_CACHING); #endif - free_page ((u32)(dev_82596.mem_start)); - dev_82596.priv = NULL; + free_page ((u32)(dev_82596->mem_start)); #ifdef ENABLE_APRICOT /* If we don't do this, we can't re-insmod it later. */ - release_region(dev_82596.base_addr, I596_TOTAL_SIZE); + release_region(dev_82596->base_addr, I596_TOTAL_SIZE); #endif + free_netdev(dev_82596); } #endif /* MODULE */ diff -Nru a/drivers/net/8390.c b/drivers/net/8390.c --- a/drivers/net/8390.c Thu Jan 22 18:59:23 2004 +++ b/drivers/net/8390.c Thu Jan 22 18:59:23 2004 @@ -157,15 +157,8 @@ int ei_open(struct net_device *dev) { unsigned long flags; - struct ei_device *ei_local = (struct ei_device *) dev->priv; + struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev); - /* This can't happen unless somebody forgot to call ethdev_init(). */ - if (ei_local == NULL) - { - printk(KERN_EMERG "%s: ei_open passed a non-existent device!\n", dev->name); - return -ENXIO; - } - /* The card I/O part of the driver (e.g. 3c503) can hook a Tx timeout wrapper that does e.g. media check & then calls ei_tx_timeout. */ if (dev->tx_timeout == NULL) @@ -196,7 +189,7 @@ */ int ei_close(struct net_device *dev) { - struct ei_device *ei_local = (struct ei_device *) dev->priv; + struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev); unsigned long flags; /* @@ -221,7 +214,7 @@ void ei_tx_timeout(struct net_device *dev) { long e8390_base = dev->base_addr; - struct ei_device *ei_local = (struct ei_device *) dev->priv; + struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev); int txsr, isr, tickssofar = jiffies - dev->trans_start; unsigned long flags; @@ -267,7 +260,7 @@ static int ei_start_xmit(struct sk_buff *skb, struct net_device *dev) { long e8390_base = dev->base_addr; - struct ei_device *ei_local = (struct ei_device *) dev->priv; + struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev); int length, send_length, output_page; unsigned long flags; char scratch[ETH_ZLEN]; @@ -435,7 +428,7 @@ } e8390_base = dev->base_addr; - ei_local = (struct ei_device *) dev->priv; + ei_local = (struct ei_device *) netdev_priv(dev); /* * Protect the irq test too. @@ -523,6 +516,15 @@ return IRQ_HANDLED; } +#ifdef CONFIG_NET_POLL_CONTROLLER +void ei_poll(struct net_device *dev) +{ + disable_irq(dev->irq); + ei_interrupt(dev->irq, dev, NULL); + enable_irq(dev->irq); +} +#endif + /** * ei_tx_err - handle transmitter error * @dev: network device which threw the exception @@ -540,7 +542,7 @@ static void ei_tx_err(struct net_device *dev) { long e8390_base = dev->base_addr; - struct ei_device *ei_local = (struct ei_device *) dev->priv; + struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev); unsigned char txsr = inb_p(e8390_base+EN0_TSR); unsigned char tx_was_aborted = txsr & (ENTSR_ABT+ENTSR_FU); @@ -583,7 +585,7 @@ static void ei_tx_intr(struct net_device *dev) { long e8390_base = dev->base_addr; - struct ei_device *ei_local = (struct ei_device *) dev->priv; + struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev); int status = inb(e8390_base + EN0_TSR); outb_p(ENISR_TX, e8390_base + EN0_ISR); /* Ack intr. */ @@ -675,7 +677,7 @@ static void ei_receive(struct net_device *dev) { long e8390_base = dev->base_addr; - struct ei_device *ei_local = (struct ei_device *) dev->priv; + struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev); unsigned char rxing_page, this_frame, next_frame; unsigned short current_offset; int rx_pkt_count = 0; @@ -813,7 +815,7 @@ { long e8390_base = dev->base_addr; unsigned char was_txing, must_resend = 0; - struct ei_device *ei_local = (struct ei_device *) dev->priv; + struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev); /* * Record whether a Tx was in progress and then issue the @@ -881,7 +883,7 @@ static struct net_device_stats *get_stats(struct net_device *dev) { long ioaddr = dev->base_addr; - struct ei_device *ei_local = (struct ei_device *) dev->priv; + struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev); unsigned long flags; /* If the card is stopped, just return the present stats. */ @@ -936,7 +938,7 @@ { long e8390_base = dev->base_addr; int i; - struct ei_device *ei_local = (struct ei_device*)dev->priv; + struct ei_device *ei_local = (struct ei_device*)netdev_priv(dev); if (!(dev->flags&(IFF_PROMISC|IFF_ALLMULTI))) { @@ -990,53 +992,34 @@ static void set_multicast_list(struct net_device *dev) { unsigned long flags; - struct ei_device *ei_local = (struct ei_device*)dev->priv; + struct ei_device *ei_local = (struct ei_device*)netdev_priv(dev); spin_lock_irqsave(&ei_local->page_lock, flags); do_set_multicast_list(dev); spin_unlock_irqrestore(&ei_local->page_lock, flags); } -static inline void ei_device_init(struct ei_device *ei_local) -{ - spin_lock_init(&ei_local->page_lock); -} - /** - * ethdev_init - init rest of 8390 device struct + * ethdev_setup - init rest of 8390 device struct * @dev: network device structure to init * * Initialize the rest of the 8390 device structure. Do NOT __init * this, as it is used by 8390 based modular drivers too. */ -int ethdev_init(struct net_device *dev) +static void ethdev_setup(struct net_device *dev) { + struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev); if (ei_debug > 1) printk(version); - if (dev->priv == NULL) - { - dev->priv = kmalloc(sizeof(struct ei_device), GFP_KERNEL); - if (dev->priv == NULL) - return -ENOMEM; - memset(dev->priv, 0, sizeof(struct ei_device)); - ei_device_init(dev->priv); - } - dev->hard_start_xmit = &ei_start_xmit; dev->get_stats = get_stats; dev->set_multicast_list = &set_multicast_list; ether_setup(dev); - - return 0; -} -/* wrapper to make alloc_netdev happy; probably should just cast... */ -static void __ethdev_init(struct net_device *dev) -{ - ethdev_init(dev); + spin_lock_init(&ei_local->page_lock); } /** @@ -1044,15 +1027,10 @@ * * Allocate 8390-specific net_device. */ -struct net_device *alloc_ei_netdev(void) +struct net_device *__alloc_ei_netdev(int size) { - struct net_device *dev; - - dev = alloc_netdev(sizeof(struct ei_device), "eth%d", __ethdev_init); - if (dev) - ei_device_init(dev->priv); - - return dev; + return alloc_netdev(sizeof(struct ei_device) + size, "eth%d", + ethdev_setup); } @@ -1072,7 +1050,7 @@ void NS8390_init(struct net_device *dev, int startp) { long e8390_base = dev->base_addr; - struct ei_device *ei_local = (struct ei_device *) dev->priv; + struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev); int i; int endcfg = ei_local->word16 ? (0x48 | ENDCFG_WTS | (ei_local->bigendian ? ENDCFG_BOS : 0)) @@ -1136,7 +1114,7 @@ int start_page) { long e8390_base = dev->base_addr; - struct ei_device *ei_local __attribute((unused)) = (struct ei_device *) dev->priv; + struct ei_device *ei_local __attribute((unused)) = (struct ei_device *) netdev_priv(dev); outb_p(E8390_NODMA+E8390_PAGE0, e8390_base+E8390_CMD); @@ -1155,10 +1133,12 @@ EXPORT_SYMBOL(ei_open); EXPORT_SYMBOL(ei_close); EXPORT_SYMBOL(ei_interrupt); +#ifdef CONFIG_NET_POLL_CONTROLLER +EXPORT_SYMBOL(ei_poll); +#endif EXPORT_SYMBOL(ei_tx_timeout); -EXPORT_SYMBOL(ethdev_init); EXPORT_SYMBOL(NS8390_init); -EXPORT_SYMBOL(alloc_ei_netdev); +EXPORT_SYMBOL(__alloc_ei_netdev); #if defined(MODULE) diff -Nru a/drivers/net/8390.h b/drivers/net/8390.h --- a/drivers/net/8390.h Thu Jan 22 18:59:26 2004 +++ b/drivers/net/8390.h Thu Jan 22 18:59:26 2004 @@ -39,12 +39,19 @@ #define ei_debug 1 #endif -extern int ethdev_init(struct net_device *dev); +#ifdef CONFIG_NET_POLL_CONTROLLER +extern void ei_poll(struct net_device *dev); +#endif + extern void NS8390_init(struct net_device *dev, int startp); extern int ei_open(struct net_device *dev); extern int ei_close(struct net_device *dev); extern irqreturn_t ei_interrupt(int irq, void *dev_id, struct pt_regs *regs); -extern struct net_device *alloc_ei_netdev(void); +extern struct net_device *__alloc_ei_netdev(int size); +static inline struct net_device *alloc_ei_netdev(void) +{ + return __alloc_ei_netdev(0); +} /* You have one of these per-board */ struct ei_device { @@ -84,7 +91,7 @@ /* The maximum time waited (in jiffies) before assuming a Tx failed. (20ms) */ #define TX_TIMEOUT (20*HZ/100) -#define ei_status (*(struct ei_device *)(dev->priv)) +#define ei_status (*(struct ei_device *)netdev_priv(dev)) /* Some generic ethernet register configurations. */ #define E8390_TX_IRQ_MASK 0xa /* For register EN0_ISR */ diff -Nru a/drivers/net/Kconfig b/drivers/net/Kconfig --- a/drivers/net/Kconfig Thu Jan 22 18:59:26 2004 +++ b/drivers/net/Kconfig Thu Jan 22 18:59:26 2004 @@ -1354,8 +1354,9 @@ say N. config E100 - tristate "EtherExpressPro/100 support (e100, Alternate Intel driver)" + tristate "Intel(R) PRO/100+ support" depends on NET_PCI && PCI + select MII ---help--- This driver supports Intel(R) PRO/100 family of adapters, which includes: @@ -1428,6 +1429,10 @@ . The module will be called e100. +config E100_NAPI + bool "Use Rx Polling (NAPI)" + depends on E100 + config LNE390 tristate "Mylex EISA LNE390A/B support (EXPERIMENTAL)" depends on NET_PCI && EISA && EXPERIMENTAL @@ -1577,6 +1582,24 @@ experience problems, you can enable this option to restore the old RX-reset behavior. If unsure, say N. +config 8139_RXBUF_IDX + int "Receive ring size (0 => 8K, 1 => 16K, 2 => 32K, 3 => 64K)" + depends on 8139TOO + range 0 3 + default 1 if EMBEDDED || SH_DREAMCAST + default 2 + help + The 8139too driver has a fixed area of memory for receiving data. + The default value is adequate for most systems. The 64KB + ring size has hardware issues that may cause problems. + Values: + 0 => 8 KB + 1 => 16 KB embedded systems + 2 => 32 KB default for most systems + 3 => 64 KB + If unsure, use the default 2. + + config SIS900 tristate "SiS 900/7016 PCI Fast Ethernet Adapter support" depends on NET_PCI && PCI @@ -2457,6 +2480,13 @@ To compile this driver as a module, choose M here: the module will be called shaper. If unsure, say N. + +config NETCONSOLE + tristate "Network console logging support (EXPERIMENTAL)" + depends on NETDEVICES && EXPERIMENTAL + ---help--- + If you want to log kernel messages over the network, enable this. + See Documentation/networking/netconsole.txt for details. source "drivers/net/wan/Kconfig" diff -Nru a/drivers/net/Makefile b/drivers/net/Makefile --- a/drivers/net/Makefile Thu Jan 22 18:59:24 2004 +++ b/drivers/net/Makefile Thu Jan 22 18:59:24 2004 @@ -8,7 +8,6 @@ obj-$(CONFIG_ISDN) += slhc.o endif -obj-$(CONFIG_E100) += e100/ obj-$(CONFIG_E1000) += e1000/ obj-$(CONFIG_IXGB) += ixgb/ obj-$(CONFIG_BONDING) += bonding/ @@ -39,6 +38,7 @@ obj-$(CONFIG_NE2K_PCI) += ne2k-pci.o 8390.o obj-$(CONFIG_PCNET32) += pcnet32.o obj-$(CONFIG_EEPRO100) += eepro100.o +obj-$(CONFIG_E100) += e100.o obj-$(CONFIG_TLAN) += tlan.o obj-$(CONFIG_EPIC100) += epic100.o obj-$(CONFIG_SIS190) += sis190.o @@ -112,7 +112,6 @@ obj-$(CONFIG_DUMMY) += dummy.o obj-$(CONFIG_DE600) += de600.o obj-$(CONFIG_DE620) += de620.o -obj-$(CONFIG_AT1500) += lance.o obj-$(CONFIG_LANCE) += lance.o obj-$(CONFIG_SUN3_82586) += sun3_82586.o obj-$(CONFIG_SUN3LANCE) += sun3lance.o @@ -189,3 +188,4 @@ obj-$(CONFIG_HAMRADIO) += hamradio/ obj-$(CONFIG_IRDA) += irda/ +obj-$(CONFIG_NETCONSOLE) += netconsole.o diff -Nru a/drivers/net/Space.c b/drivers/net/Space.c --- a/drivers/net/Space.c Thu Jan 22 18:59:23 2004 +++ b/drivers/net/Space.c Thu Jan 22 18:59:23 2004 @@ -40,63 +40,62 @@ ethernet adaptor have the name "eth[0123...]". */ -extern int ne2_probe(struct net_device *dev); -extern int hp100_probe(struct net_device *dev); -extern int ultra_probe(struct net_device *dev); -extern int ultra32_probe(struct net_device *dev); -extern int wd_probe(struct net_device *dev); -extern int el2_probe(struct net_device *dev); -extern int ne_probe(struct net_device *dev); -extern int hp_probe(struct net_device *dev); -extern int hp_plus_probe(struct net_device *dev); -extern int express_probe(struct net_device *); -extern int eepro_probe(struct net_device *); -extern int at1500_probe(struct net_device *); -extern int at1700_probe(struct net_device *); -extern int fmv18x_probe(struct net_device *); -extern int eth16i_probe(struct net_device *); -extern int i82596_probe(struct net_device *); -extern int ewrk3_probe(struct net_device *); -extern int el1_probe(struct net_device *); -extern int wavelan_probe(struct net_device *); -extern int arlan_probe(struct net_device *); -extern int el16_probe(struct net_device *); -extern int elmc_probe(struct net_device *); -extern int skmca_probe(struct net_device *); -extern int elplus_probe(struct net_device *); -extern int ac3200_probe(struct net_device *); -extern int es_probe(struct net_device *); -extern int lne390_probe(struct net_device *); -extern int e2100_probe(struct net_device *); -extern int ni5010_probe(struct net_device *); -extern int ni52_probe(struct net_device *); -extern int ni65_probe(struct net_device *); -extern int sonic_probe(struct net_device *); -extern int SK_init(struct net_device *); -extern int seeq8005_probe(struct net_device *); -extern int smc_init( struct net_device * ); -extern int atarilance_probe(struct net_device *); -extern int sun3lance_probe(struct net_device *); -extern int sun3_82586_probe(struct net_device *); -extern int apne_probe(struct net_device *); -extern int bionet_probe(struct net_device *); -extern int pamsnet_probe(struct net_device *); -extern int cs89x0_probe(struct net_device *dev); -extern int hplance_probe(struct net_device *dev); -extern int bagetlance_probe(struct net_device *); -extern int mvme147lance_probe(struct net_device *dev); -extern int tc515_probe(struct net_device *dev); -extern int lance_probe(struct net_device *dev); -extern int mace_probe(struct net_device *dev); -extern int macsonic_probe(struct net_device *dev); -extern int mac8390_probe(struct net_device *dev); -extern int mac89x0_probe(struct net_device *dev); -extern int mc32_probe(struct net_device *dev); +extern struct net_device *ne2_probe(int unit); +extern struct net_device *hp100_probe(int unit); +extern struct net_device *ultra_probe(int unit); +extern struct net_device *ultra32_probe(int unit); +extern struct net_device *wd_probe(int unit); +extern struct net_device *el2_probe(int unit); +extern struct net_device *ne_probe(int unit); +extern struct net_device *hp_probe(int unit); +extern struct net_device *hp_plus_probe(int unit); +extern struct net_device *express_probe(int unit); +extern struct net_device *eepro_probe(int unit); +extern struct net_device *at1700_probe(int unit); +extern struct net_device *fmv18x_probe(int unit); +extern struct net_device *eth16i_probe(int unit); +extern struct net_device *i82596_probe(int unit); +extern struct net_device *ewrk3_probe(int unit); +extern struct net_device *el1_probe(int unit); +extern struct net_device *wavelan_probe(int unit); +extern struct net_device *arlan_probe(int unit); +extern struct net_device *el16_probe(int unit); +extern struct net_device *elmc_probe(int unit); +extern struct net_device *skmca_probe(int unit); +extern struct net_device *elplus_probe(int unit); +extern struct net_device *ac3200_probe(int unit); +extern struct net_device *es_probe(int unit); +extern struct net_device *lne390_probe(int unit); +extern struct net_device *e2100_probe(int unit); +extern struct net_device *ni5010_probe(int unit); +extern struct net_device *ni52_probe(int unit); +extern struct net_device *ni65_probe(int unit); +extern struct net_device *sonic_probe(int unit); +extern struct net_device *SK_init(int unit); +extern struct net_device *seeq8005_probe(int unit); +extern struct net_device *smc_init(int unit); +extern struct net_device *atarilance_probe(int unit); +extern struct net_device *sun3lance_probe(int unit); +extern struct net_device *sun3_82586_probe(int unit); +extern struct net_device *apne_probe(int unit); +extern struct net_device *bionet_probe(int unit); +extern struct net_device *pamsnet_probe(int unit); +extern struct net_device *cs89x0_probe(int unit); +extern struct net_device *hplance_probe(int unit); +extern struct net_device *bagetlance_probe(int unit); +extern struct net_device *mvme147lance_probe(int unit); +extern struct net_device *tc515_probe(int unit); +extern struct net_device *lance_probe(int unit); +extern struct net_device *mace_probe(int unit); +extern struct net_device *macsonic_probe(int unit); +extern struct net_device *mac8390_probe(int unit); +extern struct net_device *mac89x0_probe(int unit); +extern struct net_device *mc32_probe(int unit); extern struct net_device *cops_probe(int unit); extern struct net_device *ltpc_probe(void); /* Detachable devices ("pocket adaptors") */ -extern int de620_probe(struct net_device *); +extern struct net_device *de620_probe(int unit); /* Fibre Channel adapters */ extern int iph5526_probe(struct net_device *dev); @@ -104,33 +103,22 @@ /* SBNI adapters */ extern int sbni_probe(int unit); -struct devprobe -{ - int (*probe)(struct net_device *dev); +struct devprobe2 { + struct net_device *(*probe)(int unit); int status; /* non-zero if autoprobe has failed */ }; -/* - * probe_list walks a list of probe functions and calls each so long - * as a non-zero ioaddr is given, or as long as it hasn't already failed - * to find a card in the past (as recorded by "status") when asked to - * autoprobe (i.e. a probe that fails to find a card when autoprobing - * will not be asked to autoprobe again). It exits when a card is found. - */ -static int __init probe_list(struct net_device *dev, struct devprobe *plist) +static int __init probe_list2(int unit, struct devprobe2 *p, int autoprobe) { - struct devprobe *p = plist; - unsigned long base_addr = dev->base_addr; - - while (p->probe != NULL) { - if (base_addr && p->probe(dev) == 0) /* probe given addr */ + struct net_device *dev; + for (; p->probe; p++) { + if (autoprobe && p->status) + continue; + dev = p->probe(unit); + if (!IS_ERR(dev)) return 0; - else if (p->status == 0) { /* has autoprobe failed yet? */ - p->status = p->probe(dev); /* no, try autoprobe */ - if (p->status == 0) - return 0; - } - p++; + if (autoprobe) + p->status = PTR_ERR(dev); } return -ENODEV; } @@ -141,7 +129,8 @@ * drivers that probe for EISA cards (in the ISA group). These are the * legacy EISA only driver probes, and also the legacy PCI probes */ -static struct devprobe eisa_probes[] __initdata = { + +static struct devprobe2 eisa_probes[] __initdata = { #ifdef CONFIG_ULTRA32 {ultra32_probe, 0}, #endif @@ -157,8 +146,7 @@ {NULL, 0}, }; - -static struct devprobe mca_probes[] __initdata = { +static struct devprobe2 mca_probes[] __initdata = { #ifdef CONFIG_NE2_MCA {ne2_probe, 0}, #endif @@ -178,7 +166,7 @@ * ISA probes that touch addresses < 0x400 (including those that also * look for EISA/PCI/MCA cards in addition to ISA cards). */ -static struct devprobe isa_probes[] __initdata = { +static struct devprobe2 isa_probes[] __initdata = { #ifdef CONFIG_HP100 /* ISA, EISA & PCI */ {hp100_probe, 0}, #endif @@ -215,9 +203,6 @@ #ifdef CONFIG_SEEQ8005 {seeq8005_probe, 0}, #endif -#ifdef CONFIG_AT1500 - {at1500_probe, 0}, -#endif #ifdef CONFIG_CS89x0 {cs89x0_probe, 0}, #endif @@ -272,14 +257,14 @@ {NULL, 0}, }; -static struct devprobe parport_probes[] __initdata = { +static struct devprobe2 parport_probes[] __initdata = { #ifdef CONFIG_DE620 /* D-Link DE-620 adapter */ {de620_probe, 0}, #endif {NULL, 0}, }; -static struct devprobe m68k_probes[] __initdata = { +static struct devprobe2 m68k_probes[] __initdata = { #ifdef CONFIG_ATARILANCE /* Lance-based Atari ethernet boards */ {atarilance_probe, 0}, #endif @@ -319,7 +304,7 @@ {NULL, 0}, }; -static struct devprobe mips_probes[] __initdata = { +static struct devprobe2 mips_probes[] __initdata = { #ifdef CONFIG_MIPS_JAZZ_SONIC {sonic_probe, 0}, #endif @@ -334,83 +319,65 @@ * per bus interface. This drives the legacy devices only for now. */ -static int __init ethif_probe(int unit) +static void __init ethif_probe2(int unit) { - struct net_device *dev; - int err = -ENODEV; + unsigned long base_addr = netdev_boot_base("eth", unit); - dev = alloc_etherdev(0); - if (!dev) - return -ENOMEM; - - sprintf(dev->name, "eth%d", unit); - netdev_boot_setup_check(dev); - - /* - * Backwards compatibility - historically an I/O base of 1 was - * used to indicate not to probe for this ethN interface - */ - if (__dev_get_by_name(dev->name) || dev->base_addr == 1) { - free_netdev(dev); - return -ENXIO; - } - - /* - * The arch specific probes are 1st so that any on-board ethernet - * will be probed before other ISA/EISA/MCA/PCI bus cards. - */ - if (probe_list(dev, m68k_probes) == 0 || - probe_list(dev, mips_probes) == 0 || - probe_list(dev, eisa_probes) == 0 || - probe_list(dev, mca_probes) == 0 || - probe_list(dev, isa_probes) == 0 || - probe_list(dev, parport_probes) == 0) - err = register_netdev(dev); - - if (err) - free_netdev(dev); - return err; + if (base_addr == 1) + return; + (void)( probe_list2(unit, m68k_probes, base_addr == 0) && + probe_list2(unit, mips_probes, base_addr == 0) && + probe_list2(unit, eisa_probes, base_addr == 0) && + probe_list2(unit, mca_probes, base_addr == 0) && + probe_list2(unit, isa_probes, base_addr == 0) && + probe_list2(unit, parport_probes, base_addr == 0)); } #ifdef CONFIG_TR /* Token-ring device probe */ -extern int ibmtr_probe(struct net_device *); -extern int sk_isa_probe(struct net_device *); -extern int proteon_probe(struct net_device *); -extern int smctr_probe(struct net_device *); +extern int ibmtr_probe_card(struct net_device *); +extern struct net_device *sk_isa_probe(int unit); +extern struct net_device *proteon_probe(int unit); +extern struct net_device *smctr_probe(int unit); + +static struct devprobe2 tr_probes2[] __initdata = { +#ifdef CONFIG_SKISA + {sk_isa_probe, 0}, +#endif +#ifdef CONFIG_PROTEON + {proteon_probe, 0}, +#endif +#ifdef CONFIG_SMCTR + {smctr_probe, 0}, +#endif + {NULL, 0}, +}; static __init int trif_probe(int unit) { - struct net_device *dev; int err = -ENODEV; - - dev = alloc_trdev(0); +#ifdef CONFIG_IBMTR + struct net_device *dev = alloc_trdev(0); if (!dev) return -ENOMEM; sprintf(dev->name, "tr%d", unit); netdev_boot_setup_check(dev); - if ( -#ifdef CONFIG_IBMTR - ibmtr_probe(dev) == 0 || -#endif -#ifdef CONFIG_SKISA - sk_isa_probe(dev) == 0 || -#endif -#ifdef CONFIG_PROTEON - proteon_probe(dev) == 0 || -#endif -#ifdef CONFIG_SMCTR - smctr_probe(dev) == 0 || -#endif - 0 ) - err = register_netdev(dev); - + err = ibmtr_probe_card(dev); if (err) free_netdev(dev); +#endif return err; +} + +static void __init trif_probe2(int unit) +{ + unsigned long base_addr = netdev_boot_base("tr", unit); + if (base_addr == 1) + return; + probe_list2(unit, tr_probes2, base_addr == 0); } #endif @@ -437,10 +404,11 @@ #endif #ifdef CONFIG_TR for (num = 0; num < 8; ++num) - trif_probe(num); + if (!trif_probe(num)) + trif_probe2(num); #endif for (num = 0; num < 8; ++num) - ethif_probe(num); + ethif_probe2(num); #ifdef CONFIG_COPS cops_probe(0); diff -Nru a/drivers/net/a2065.c b/drivers/net/a2065.c --- a/drivers/net/a2065.c Thu Jan 22 18:59:25 2004 +++ b/drivers/net/a2065.c Thu Jan 22 18:59:25 2004 @@ -737,7 +737,7 @@ continue; } - dev = init_etherdev(NULL, sizeof(struct lance_private)); + dev = alloc_etherdev(sizeof(struct lance_private)); if (dev == NULL) { release_resource(r1); @@ -791,17 +791,22 @@ dev->set_multicast_list = &lance_set_multicast; dev->dma = 0; -#ifdef MODULE - priv->next_module = root_a2065_dev; - root_a2065_dev = priv; -#endif - ether_setup(dev); init_timer(&priv->multicast_timer); priv->multicast_timer.data = (unsigned long) dev; priv->multicast_timer.function = (void (*)(unsigned long)) &lance_set_multicast; - res = 0; + res = register_netdev(dev); + if (res) { + release_resource(r1); + release_resource(r2); + free_netdev(dev); + break; + } +#ifdef MODULE + priv->next_module = root_a2065_dev; + root_a2065_dev = priv; +#endif } return res; } diff -Nru a/drivers/net/ac3200.c b/drivers/net/ac3200.c --- a/drivers/net/ac3200.c Thu Jan 22 18:59:26 2004 +++ b/drivers/net/ac3200.c Thu Jan 22 18:59:26 2004 @@ -75,7 +75,6 @@ #define AC_START_PG 0x00 /* First page of 8390 TX buffer */ #define AC_STOP_PG 0x80 /* Last page +1 of the 8390 RX ring */ -int ac3200_probe(struct net_device *dev); static int ac_probe1(int ioaddr, struct net_device *dev); static int ac_open(struct net_device *dev); @@ -96,9 +95,11 @@ or the unique value in the station address PROM. */ -int __init ac3200_probe(struct net_device *dev) +static int __init do_ac3200_probe(struct net_device *dev) { unsigned short ioaddr = dev->base_addr; + int irq = dev->irq; + int mem_start = dev->mem_start; SET_MODULE_OWNER(dev); @@ -110,13 +111,50 @@ if ( ! EISA_bus) return -ENXIO; - for (ioaddr = 0x1000; ioaddr < 0x9000; ioaddr += 0x1000) + for (ioaddr = 0x1000; ioaddr < 0x9000; ioaddr += 0x1000) { if (ac_probe1(ioaddr, dev) == 0) return 0; + dev->irq = irq; + dev->mem_start = mem_start; + } return -ENODEV; } +static void cleanup_card(struct net_device *dev) +{ + /* Someday free_irq may be in ac_close_card() */ + free_irq(dev->irq, dev); + release_region(dev->base_addr, AC_IO_EXTENT); + if (ei_status.reg0) + iounmap((void *)dev->mem_start); +} + +struct net_device * __init ac3200_probe(int unit) +{ + struct net_device *dev = alloc_ei_netdev(); + int err; + + if (!dev) + return ERR_PTR(-ENOMEM); + + sprintf(dev->name, "eth%d", unit); + netdev_boot_setup_check(dev); + + err = do_ac3200_probe(dev); + if (err) + goto out; + err = register_netdev(dev); + if (err) + goto out1; + return dev; +out1: + cleanup_card(dev); +out: + free_netdev(dev); + return ERR_PTR(err); +} + static int __init ac_probe1(int ioaddr, struct net_device *dev) { int i, retval; @@ -156,13 +194,6 @@ } #endif - /* Allocate dev->priv and fill in 8390 specific dev fields. */ - if (ethdev_init(dev)) { - printk (", unable to allocate memory for dev->priv.\n"); - retval = -ENOMEM; - goto out; - } - /* Assign and allocate the interrupt now. */ if (dev->irq == 0) { dev->irq = config2irq(inb(ioaddr + AC_CONFIG)); @@ -210,7 +241,7 @@ printk(KERN_CRIT "ac3200.c: or to an address above 0x%lx.\n", virt_to_phys(high_memory)); printk(KERN_CRIT "ac3200.c: Driver NOT installed.\n"); retval = -EINVAL; - goto out2; + goto out1; } dev->mem_start = (unsigned long)ioremap(dev->mem_start, AC_STOP_PG*0x100); if (dev->mem_start == 0) { @@ -218,7 +249,7 @@ printk(KERN_ERR "ac3200.c: Try using EISA SCU to set memory below 1MB.\n"); printk(KERN_ERR "ac3200.c: Driver NOT installed.\n"); retval = -EINVAL; - goto out2; + goto out1; } ei_status.reg0 = 1; /* Use as remap flag */ printk("ac3200.c: remapped %dkB card memory to virtual address %#lx\n", @@ -245,13 +276,13 @@ dev->open = &ac_open; dev->stop = &ac_close_card; +#ifdef CONFIG_NET_POLL_CONTROLLER + dev->poll_controller = ei_poll; +#endif NS8390_init(dev, 0); return 0; -out2: - free_irq(dev->irq, dev); out1: - kfree(dev->priv); - dev->priv = NULL; + free_irq(dev->irq, dev); out: release_region(ioaddr, AC_IO_EXTENT); return retval; @@ -338,7 +369,7 @@ #ifdef MODULE #define MAX_AC32_CARDS 4 /* Max number of AC32 cards per module */ -static struct net_device dev_ac32[MAX_AC32_CARDS]; +static struct net_device *dev_ac32[MAX_AC32_CARDS]; static int io[MAX_AC32_CARDS]; static int irq[MAX_AC32_CARDS]; static int mem[MAX_AC32_CARDS]; @@ -354,26 +385,32 @@ int init_module(void) { + struct net_device *dev; int this_dev, found = 0; for (this_dev = 0; this_dev < MAX_AC32_CARDS; this_dev++) { - struct net_device *dev = &dev_ac32[this_dev]; + if (io[this_dev] == 0 && this_dev != 0) + break; + dev = alloc_ei_netdev(); + if (!dev) + break; dev->irq = irq[this_dev]; dev->base_addr = io[this_dev]; dev->mem_start = mem[this_dev]; /* Currently ignored by driver */ - dev->init = ac3200_probe; - /* Default is to only install one card. */ - if (io[this_dev] == 0 && this_dev != 0) break; - if (register_netdev(dev) != 0) { - printk(KERN_WARNING "ac3200.c: No ac3200 card found (i/o = 0x%x).\n", io[this_dev]); - if (found != 0) { /* Got at least one. */ - return 0; + if (do_ac3200_probe(dev) == 0) { + if (register_netdev(dev) == 0) { + dev_ac32[found++] = dev; + continue; } - return -ENXIO; + cleanup_card(dev); } - found++; + free_netdev(dev); + printk(KERN_WARNING "ac3200.c: No ac3200 card found (i/o = 0x%x).\n", io[this_dev]); + break; } - return 0; + if (found) + return 0; + return -ENXIO; } void @@ -382,16 +419,11 @@ int this_dev; for (this_dev = 0; this_dev < MAX_AC32_CARDS; this_dev++) { - struct net_device *dev = &dev_ac32[this_dev]; - if (dev->priv != NULL) { - /* Someday free_irq may be in ac_close_card() */ - free_irq(dev->irq, dev); - release_region(dev->base_addr, AC_IO_EXTENT); - if (ei_status.reg0) - iounmap((void *)dev->mem_start); + struct net_device *dev = dev_ac32[this_dev]; + if (dev) { unregister_netdev(dev); - kfree(dev->priv); - dev->priv = NULL; + cleanup_card(dev); + free_netdev(dev); } } } diff -Nru a/drivers/net/acenic.c b/drivers/net/acenic.c --- a/drivers/net/acenic.c Thu Jan 22 18:59:25 2004 +++ b/drivers/net/acenic.c Thu Jan 22 18:59:25 2004 @@ -731,12 +731,6 @@ break; } - if (register_netdev(dev)) { - printk(KERN_ERR "acenic: device registration failed\n"); - free_netdev(dev); - continue; - } - switch(pdev->vendor) { case PCI_VENDOR_ID_ALTEON: if (pdev->device == PCI_DEVICE_ID_FARALLON_PN9100T) { @@ -824,6 +818,13 @@ continue; } + if (register_netdev(dev)) { + printk(KERN_ERR "acenic: device registration failed\n"); + ace_init_cleanup(dev); + free_netdev(dev); + continue; + } + if (ap->pci_using_dac) dev->features |= NETIF_F_HIGHDMA; @@ -874,6 +875,7 @@ while (root_dev) { ap = root_dev->priv; next = ap->next; + unregister_netdev(root_dev); regs = ap->regs; @@ -1133,7 +1135,6 @@ if (dev->irq) free_irq(dev->irq, dev); - unregister_netdev(dev); iounmap(ap->regs); } diff -Nru a/drivers/net/amd8111e.c b/drivers/net/amd8111e.c --- a/drivers/net/amd8111e.c Thu Jan 22 18:59:25 2004 +++ b/drivers/net/amd8111e.c Thu Jan 22 18:59:25 2004 @@ -1153,6 +1153,17 @@ return IRQ_RETVAL(handled); } +#ifdef CONFIG_NET_POLL_CONTROLLER +static void amd8111e_poll(struct net_device *dev) +{ + unsigned long flags; + local_save_flags(flags); + local_irq_disable(); + amd8111e_interrupt(0, dev, NULL); + local_irq_restore(flags); +} +#endif + /* This function closes the network interface and updates the statistics so that most recent statistics will be available after the interface is down. */ @@ -1884,6 +1895,9 @@ dev->irq =pdev->irq; dev->tx_timeout = amd8111e_tx_timeout; dev->watchdog_timeo = AMD8111E_TX_TIMEOUT; +#ifdef CONFIG_NET_POLL_CONTROLLER + dev->poll_controller = amd8111e_poll; +#endif #if AMD8111E_VLAN_TAG_USED dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX; diff -Nru a/drivers/net/apne.c b/drivers/net/apne.c --- a/drivers/net/apne.c Thu Jan 22 18:59:27 2004 +++ b/drivers/net/apne.c Thu Jan 22 18:59:27 2004 @@ -72,7 +72,7 @@ #define NESM_STOP_PG 0x80 /* Last page +1 of RX ring */ -int apne_probe(struct net_device *dev); +struct net_device * __init apne_probe(int unit); static int apne_probe1(struct net_device *dev, int ioaddr); static int apne_open(struct net_device *dev); @@ -116,28 +116,37 @@ static int apne_owned; /* signal if card already owned */ -int __init apne_probe(struct net_device *dev) +struct net_device * __init apne_probe(int unit) { + struct net_device *dev; #ifndef MANUAL_CONFIG char tuple[8]; #endif + int err; if (apne_owned) - return -ENODEV; - - SET_MODULE_OWNER(dev); + return ERR_PTR(-ENODEV); if ( !(AMIGAHW_PRESENT(PCMCIA)) ) - return (-ENODEV); + return ERR_PTR(-ENODEV); printk("Looking for PCMCIA ethernet card : "); /* check if a card is inserted */ if (!(PCMCIA_INSERTED)) { printk("NO PCMCIA card inserted\n"); - return (-ENODEV); + return ERR_PTR(-ENODEV); } - + + dev = alloc_ei_netdev(); + if (!dev) + return ERR_PTR(-ENOMEM); + if (unit >= 0) { + sprintf(dev->name, "eth%d", unit); + netdev_boot_setup_check(dev); + } + SET_MODULE_OWNER(dev); + /* disable pcmcia irq for readtuple */ pcmcia_disable_irq(); @@ -145,17 +154,41 @@ if ((pcmcia_copy_tuple(CISTPL_FUNCID, tuple, 8) < 3) || (tuple[2] != CISTPL_FUNCID_NETWORK)) { printk("not an ethernet card\n"); - return (-ENODEV); + /* XXX: shouldn't we re-enable irq here? */ + free_netdev(dev); + return ERR_PTR(-ENODEV); } #endif printk("ethernet PCMCIA card inserted\n"); - if (init_pcmcia()) - return apne_probe1(dev, IOBASE); - else - return (-ENODEV); + if (!init_pcmcia()) { + /* XXX: shouldn't we re-enable irq here? */ + free_netdev(dev); + return ERR_PTR(-ENODEV); + } + + if (!request_region(IOBASE, 0x20, dev->name)) { + free_netdev(dev); + return ERR_PTR(-EBUSY); + } + + err = apne_probe1(dev, IOBASE); + if (err) { + release_region(IOBASE, 0x20); + free_netdev(dev); + return ERR_PTR(err); + } + err = register_netdev(dev); + if (!err) + return dev; + pcmcia_disable_irq(); + free_irq(IRQ_AMIGA_PORTS, dev); + pcmcia_reset(); + release_region(IOBASE, 0x20); + free_netdev(dev); + return ERR_PTR(err); } static int __init apne_probe1(struct net_device *dev, int ioaddr) @@ -280,13 +313,6 @@ i = request_irq(IRQ_AMIGA_PORTS, apne_interrupt, SA_SHIRQ, dev->name, dev); if (i) return i; - /* Allocate dev->priv and fill in 8390 specific dev fields. */ - if (ethdev_init(dev)) { - printk (" unable to get memory for dev->priv.\n"); - free_irq(IRQ_AMIGA_PORTS, dev); - return -ENOMEM; - } - for(i = 0; i < ETHER_ADDR_LEN; i++) { printk(" %2.2x", SA_prom[i]); dev->dev_addr[i] = SA_prom[i]; @@ -307,6 +333,9 @@ ei_status.get_8390_hdr = &apne_get_8390_hdr; dev->open = &apne_open; dev->stop = &apne_close; +#ifdef CONFIG_NET_POLL_CONTROLLER + dev->poll_controller = ei_poll; +#endif NS8390_init(dev, 0); pcmcia_ack_int(pcmcia_get_intreq()); /* ack PCMCIA int req */ @@ -534,32 +563,29 @@ } #ifdef MODULE -static struct net_device apne_dev; +static struct net_device *apne_dev; int init_module(void) { - int err; - - apne_dev.init = apne_probe; - if ((err = register_netdev(&apne_dev))) { - if (err == -EIO) - printk("No PCMCIA NEx000 ethernet card found.\n"); - return (err); - } - return (0); + apne_dev = apne_probe(-1); + if (IS_ERR(apne_dev)) + return PTR_ERR(apne_dev); + return 0; } void cleanup_module(void) { - unregister_netdev(&apne_dev); + unregister_netdev(apne_dev); pcmcia_disable_irq(); - free_irq(IRQ_AMIGA_PORTS, &apne_dev); + free_irq(IRQ_AMIGA_PORTS, apne_dev); pcmcia_reset(); - apne_owned = 0; + release_region(IOBASE, 0x20); + + free_netdev(apne_dev); } #endif diff -Nru a/drivers/net/appletalk/cops.c b/drivers/net/appletalk/cops.c --- a/drivers/net/appletalk/cops.c Thu Jan 22 18:59:25 2004 +++ b/drivers/net/appletalk/cops.c Thu Jan 22 18:59:25 2004 @@ -262,7 +262,7 @@ out1: cleanup_card(dev); out: - kfree(dev); + free_netdev(dev); return ERR_PTR(err); } diff -Nru a/drivers/net/appletalk/ipddp.c b/drivers/net/appletalk/ipddp.c --- a/drivers/net/appletalk/ipddp.c Thu Jan 22 18:59:23 2004 +++ b/drivers/net/appletalk/ipddp.c Thu Jan 22 18:59:23 2004 @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -55,34 +56,24 @@ static int ipddp_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd); -static int __init ipddp_init(struct net_device *dev) +static struct net_device * __init ipddp_init(void) { static unsigned version_printed; + struct net_device *dev; + int err; + + dev = alloc_etherdev(sizeof(struct net_device_stats)); + if (!dev) + return ERR_PTR(-ENOMEM); SET_MODULE_OWNER(dev); + strcpy(dev->name, "ipddp%d"); if (version_printed++ == 0) printk(version); - /* Let the user now what mode we are in */ - if(ipddp_mode == IPDDP_ENCAP) - printk("%s: Appletalk-IP Encap. mode by Bradford W. Johnson \n", - dev->name); - if(ipddp_mode == IPDDP_DECAP) - printk("%s: Appletalk-IP Decap. mode by Jay Schulist \n", - dev->name); - - /* Fill in the device structure with ethernet-generic values. */ - ether_setup(dev); - /* Initalize the device structure. */ dev->hard_start_xmit = ipddp_xmit; - - dev->priv = kmalloc(sizeof(struct net_device_stats), GFP_KERNEL); - if(!dev->priv) - return -ENOMEM; - memset(dev->priv,0,sizeof(struct net_device_stats)); - dev->get_stats = ipddp_get_stats; dev->do_ioctl = ipddp_ioctl; @@ -97,7 +88,21 @@ */ dev->hard_header_len = 14+8+sizeof(struct ddpehdr)+1; - return 0; + err = register_netdev(dev); + if (err) { + free_netdev(dev); + return ERR_PTR(err); + } + + /* Let the user now what mode we are in */ + if(ipddp_mode == IPDDP_ENCAP) + printk("%s: Appletalk-IP Encap. mode by Bradford W. Johnson \n", + dev->name); + if(ipddp_mode == IPDDP_DECAP) + printk("%s: Appletalk-IP Decap. mode by Jay Schulist \n", + dev->name); + + return dev; } /* @@ -281,23 +286,16 @@ } } -static struct net_device dev_ipddp; +static struct net_device *dev_ipddp; MODULE_LICENSE("GPL"); MODULE_PARM(ipddp_mode, "i"); static int __init ipddp_init_module(void) { - int err; - - dev_ipddp.init = ipddp_init; - err=dev_alloc_name(&dev_ipddp, "ipddp%d"); - if(err < 0) - return err; - - if(register_netdev(&dev_ipddp) != 0) - return -EIO; - + dev_ipddp = ipddp_init(); + if (IS_ERR(dev_ipddp)) + return PTR_ERR(dev_ipddp); return 0; } @@ -305,8 +303,8 @@ { struct ipddp_route *p; - unregister_netdev(&dev_ipddp); - kfree(dev_ipddp.priv); + unregister_netdev(dev_ipddp); + free_netdev(dev_ipddp); while (ipddp_route_list) { p = ipddp_route_list->next; diff -Nru a/drivers/net/appletalk/ltpc.c b/drivers/net/appletalk/ltpc.c --- a/drivers/net/appletalk/ltpc.c Thu Jan 22 18:59:24 2004 +++ b/drivers/net/appletalk/ltpc.c Thu Jan 22 18:59:24 2004 @@ -1213,7 +1213,7 @@ out2: release_region(io, 8); out1: - kfree(dev); + free_netdev(dev); out: return ERR_PTR(err); } diff -Nru a/drivers/net/arcnet/arc-rimi.c b/drivers/net/arcnet/arc-rimi.c --- a/drivers/net/arcnet/arc-rimi.c Thu Jan 22 18:59:23 2004 +++ b/drivers/net/arcnet/arc-rimi.c Thu Jan 22 18:59:23 2004 @@ -26,6 +26,7 @@ */ #include #include +#include #include #include #include @@ -85,8 +86,6 @@ */ static int __init arcrimi_probe(struct net_device *dev) { - int retval; - BUGLVL(D_NORMAL) printk(VERSION); BUGLVL(D_NORMAL) printk("E-mail me if you actually test the RIM I driver, please!\n"); @@ -114,11 +113,7 @@ "ID!\n"); return -ENODEV; } - retval = arcrimi_found(dev); - if (retval < 0) { - release_mem_region(dev->mem_start, BUFFER_SIZE); - } - return retval; + return arcrimi_found(dev); } @@ -129,11 +124,13 @@ static int __init arcrimi_found(struct net_device *dev) { struct arcnet_local *lp; - u_long first_mirror, last_mirror, shmem; + unsigned long first_mirror, last_mirror, shmem; int mirror_size; + int err; /* reserve the irq */ if (request_irq(dev->irq, &arcnet_interrupt, 0, "arcnet (RIM I)", dev)) { + release_mem_region(dev->mem_start, BUFFER_SIZE); BUGMSG(D_NORMAL, "Can't get IRQ %d!\n", dev->irq); return -ENODEV; } @@ -168,11 +165,7 @@ /* initialize the rest of the device structure. */ - lp = dev->priv = kmalloc(sizeof(struct arcnet_local), GFP_KERNEL); - if (!lp) { - BUGMSG(D_NORMAL, "Can't allocate device data!\n"); - goto err_free_irq; - } + lp = dev->priv; lp->card_name = "RIM I"; lp->hw.command = arcrimi_command; lp->hw.status = arcrimi_status; @@ -181,18 +174,6 @@ lp->hw.owner = THIS_MODULE; lp->hw.copy_to_card = arcrimi_copy_to_card; lp->hw.copy_from_card = arcrimi_copy_from_card; - lp->mem_start = ioremap(dev->mem_start, dev->mem_end - dev->mem_start + 1); - if (!lp->mem_start) { - BUGMSG(D_NORMAL, "Can't remap device memory!\n"); - goto err_free_dev_priv; - } - /* Fill in the fields of the device structure with generic - * values. - */ - arcdev_setup(dev); - - /* get and check the station ID from offset 1 in shmem */ - dev->dev_addr[0] = readb(lp->mem_start + 1); /* * re-reserve the memory region - arcrimi_probe() alloced this reqion @@ -200,25 +181,40 @@ * with the correct size. There is a VERY slim chance this could * fail. */ - release_mem_region(dev->mem_start, BUFFER_SIZE); + release_mem_region(shmem, BUFFER_SIZE); if (!request_mem_region(dev->mem_start, dev->mem_end - dev->mem_start + 1, "arcnet (90xx)")) { BUGMSG(D_NORMAL, "Card memory already allocated\n"); - goto err_free_dev_priv; + goto err_free_irq; } + lp->mem_start = ioremap(dev->mem_start, dev->mem_end - dev->mem_start + 1); + if (!lp->mem_start) { + BUGMSG(D_NORMAL, "Can't remap device memory!\n"); + goto err_release_mem; + } + + /* get and check the station ID from offset 1 in shmem */ + dev->dev_addr[0] = readb(lp->mem_start + 1); + BUGMSG(D_NORMAL, "ARCnet RIM I: station %02Xh found at IRQ %d, " "ShMem %lXh (%ld*%d bytes).\n", dev->dev_addr[0], dev->irq, dev->mem_start, (dev->mem_end - dev->mem_start + 1) / mirror_size, mirror_size); + err = register_netdev(dev); + if (err) + goto err_unmap; + return 0; - err_free_dev_priv: - kfree(dev->priv); - err_free_irq: +err_unmap: + iounmap(lp->mem_start); +err_release_mem: + release_mem_region(dev->mem_start, dev->mem_end - dev->mem_start + 1); +err_free_irq: free_irq(dev->irq, dev); return -EIO; } @@ -294,94 +290,79 @@ TIME("memcpy_fromio", count, memcpy_fromio(buf, memaddr, count)); } -#ifdef MODULE +static int node; +static int io; /* use the insmod io= irq= node= options */ +static int irq; +static char device[9]; /* use eg. device=arc1 to change name */ + +module_param(node, int, 0); +module_param(io, int, 0); +module_param(irq, int, 0); +module_param_string(device, device, sizeof(device), 0); +MODULE_LICENSE("GPL"); static struct net_device *my_dev; -/* Module parameters */ - -static int node = 0; -static int io = 0x0; /* <--- EDIT THESE LINES FOR YOUR CONFIGURATION */ -static int irq = 0; /* or use the insmod io= irq= shmem= options */ -static char *device; /* use eg. device="arc1" to change name */ - -MODULE_PARM(node, "i"); -MODULE_PARM(io, "i"); -MODULE_PARM(irq, "i"); -MODULE_PARM(device, "s"); -MODULE_LICENSE("GPL"); - -int init_module(void) +static int __init arc_rimi_init(void) { struct net_device *dev; - int err; - dev = dev_alloc(device ? : "arc%d", &err); + dev = alloc_arcdev(device); if (!dev) - return err; + return -ENOMEM; if (node && node != 0xff) dev->dev_addr[0] = node; - dev->base_addr = io; + dev->mem_start = io; dev->irq = irq; if (dev->irq == 2) dev->irq = 9; - if (arcrimi_probe(dev)) + if (arcrimi_probe(dev)) { + free_netdev(dev); return -EIO; + } my_dev = dev; return 0; } -void cleanup_module(void) +static void __exit arc_rimi_exit(void) { struct net_device *dev = my_dev; struct arcnet_local *lp = (struct arcnet_local *) dev->priv; unregister_netdev(dev); - free_irq(dev->irq, dev); iounmap(lp->mem_start); release_mem_region(dev->mem_start, dev->mem_end - dev->mem_start + 1); - kfree(dev->priv); + free_irq(dev->irq, dev); free_netdev(dev); } -#else - +#ifndef MODULE static int __init arcrimi_setup(char *s) { - struct net_device *dev; int ints[8]; - s = get_options(s, 8, ints); if (!ints[0]) return 1; - dev = alloc_bootmem(sizeof(struct net_device)); - memset(dev, 0, sizeof(struct net_device)); - dev->init = arcrimi_probe; - switch (ints[0]) { default: /* ERROR */ printk("arcrimi: Too many arguments.\n"); case 3: /* Node ID */ - dev->dev_addr[0] = ints[3]; + node = ints[3]; case 2: /* IRQ */ - dev->irq = ints[2]; + irq = ints[2]; case 1: /* IO address */ - dev->mem_start = ints[1]; + io = ints[1]; } if (*s) - strncpy(dev->name, s, 9); - else - strcpy(dev->name, "arc%d"); - if (register_netdev(dev)) - printk(KERN_ERR "arc-rimi: Cannot register arcnet device\n"); - + snprintf(device, sizeof(device), "%s", s); return 1; } - __setup("arcrimi=", arcrimi_setup); - #endif /* MODULE */ + +module_init(arc_rimi_init) +module_exit(arc_rimi_exit) diff -Nru a/drivers/net/arcnet/arcnet.c b/drivers/net/arcnet/arcnet.c --- a/drivers/net/arcnet/arcnet.c Thu Jan 22 18:59:26 2004 +++ b/drivers/net/arcnet/arcnet.c Thu Jan 22 18:59:26 2004 @@ -92,6 +92,7 @@ EXPORT_SYMBOL(arcnet_unregister_proto); EXPORT_SYMBOL(arcnet_debug); EXPORT_SYMBOL(arcdev_setup); +EXPORT_SYMBOL(alloc_arcdev); EXPORT_SYMBOL(arcnet_interrupt); /* Internal function prototypes */ @@ -331,6 +332,11 @@ dev->rebuild_header = arcnet_rebuild_header; } +struct net_device *alloc_arcdev(char *name) +{ + return alloc_netdev(sizeof(struct arcnet_local), + name && *name ? name : "arc%d", arcdev_setup); +} /* * Open/initialize the board. This is called sometime after booting when diff -Nru a/drivers/net/arcnet/com20020-isa.c b/drivers/net/arcnet/com20020-isa.c --- a/drivers/net/arcnet/com20020-isa.c Thu Jan 22 18:59:23 2004 +++ b/drivers/net/arcnet/com20020-isa.c Thu Jan 22 18:59:23 2004 @@ -26,6 +26,7 @@ * ********************** */ #include +#include #include #include #include @@ -117,49 +118,41 @@ return err; } - -#ifdef MODULE - -static struct net_device *my_dev; - -/* Module parameters */ - static int node = 0; static int io = 0x0; /* <--- EDIT THESE LINES FOR YOUR CONFIGURATION */ static int irq = 0; /* or use the insmod io= irq= shmem= options */ -static char *device; /* use eg. device="arc1" to change name */ +static char device[9]; /* use eg. device="arc1" to change name */ static int timeout = 3; static int backplane = 0; static int clockp = 0; static int clockm = 0; -MODULE_PARM(node, "i"); -MODULE_PARM(io, "i"); -MODULE_PARM(irq, "i"); -MODULE_PARM(device, "s"); -MODULE_PARM(timeout, "i"); -MODULE_PARM(backplane, "i"); -MODULE_PARM(clockp, "i"); -MODULE_PARM(clockm, "i"); +module_param(node, int, 0); +module_param(io, int, 0); +module_param(irq, int, 0); +module_param_string(device, device, sizeof(device), 0); +module_param(timeout, int, 0); +module_param(backplane, int, 0); +module_param(clockp, int, 0); +module_param(clockm, int, 0); + MODULE_LICENSE("GPL"); -int init_module(void) +static struct net_device *my_dev; + +static int __init com20020_init(void) { struct net_device *dev; struct arcnet_local *lp; - int err; - dev = dev_alloc(device ? : "arc%d", &err); + dev = alloc_arcdev(device); if (!dev) - return err; - lp = dev->priv = kmalloc(sizeof(struct arcnet_local), GFP_KERNEL); - if (!lp) return -ENOMEM; - memset(lp, 0, sizeof(struct arcnet_local)); if (node && node != 0xff) dev->dev_addr[0] = node; + lp = dev->priv; lp->backplane = backplane; lp->clockp = clockp & 7; lp->clockm = clockm & 3; @@ -172,21 +165,24 @@ if (dev->irq == 2) dev->irq = 9; - if (com20020isa_probe(dev)) + if (com20020isa_probe(dev)) { + free_netdev(dev); return -EIO; + } my_dev = dev; return 0; } -void cleanup_module(void) +static void __exit com20020_exit(void) { - com20020_remove(my_dev); + unregister_netdev(my_dev); + free_irq(my_dev->irq, my_dev); release_region(my_dev->base_addr, ARCNET_TOTAL_SIZE); + free_netdev(my_dev); } -#else - +#ifndef MODULE static int __init com20020isa_setup(char *s) { struct net_device *dev; @@ -196,37 +192,31 @@ s = get_options(s, 8, ints); if (!ints[0]) return 1; - dev = alloc_bootmem(sizeof(struct net_device) + sizeof(struct arcnet_local)); - memset(dev, 0, sizeof(struct net_device) + sizeof(struct arcnet_local)); - lp = dev->priv = (struct arcnet_local *) (dev + 1); - dev->init = com20020isa_probe; switch (ints[0]) { default: /* ERROR */ printk("com90xx: Too many arguments.\n"); case 6: /* Timeout */ - lp->timeout = ints[6]; + timeout = ints[6]; case 5: /* CKP value */ - lp->clockp = ints[5]; + clockp = ints[5]; case 4: /* Backplane flag */ - lp->backplane = ints[4]; + backplane = ints[4]; case 3: /* Node ID */ - dev->dev_addr[0] = ints[3]; + node = ints[3]; case 2: /* IRQ */ - dev->irq = ints[2]; + irq = ints[2]; case 1: /* IO address */ - dev->base_addr = ints[1]; + io = ints[1]; } if (*s) - strncpy(dev->name, s, 9); - else - strcpy(dev->name, "arc%d"); - if (register_netdev(dev)) - printk(KERN_ERR "com20020: Cannot register arcnet device\n"); - + snprintf(device, sizeof(device), "%s", s); return 1; } __setup("com20020=", com20020isa_setup); #endif /* MODULE */ + +module_init(com20020_init) +module_exit(com20020_exit) diff -Nru a/drivers/net/arcnet/com20020-pci.c b/drivers/net/arcnet/com20020-pci.c --- a/drivers/net/arcnet/com20020-pci.c Thu Jan 22 18:59:24 2004 +++ b/drivers/net/arcnet/com20020-pci.c Thu Jan 22 18:59:24 2004 @@ -27,6 +27,7 @@ * ********************** */ #include +#include #include #include #include @@ -46,18 +47,18 @@ /* Module parameters */ static int node; -static char *device; /* use eg. device="arc1" to change name */ +static char device[9]; /* use eg. device="arc1" to change name */ static int timeout = 3; static int backplane; static int clockp; static int clockm; -MODULE_PARM(node, "i"); -MODULE_PARM(device, "s"); -MODULE_PARM(timeout, "i"); -MODULE_PARM(backplane, "i"); -MODULE_PARM(clockp, "i"); -MODULE_PARM(clockm, "i"); +module_param(node, int, 0); +module_param_string(device, device, sizeof(device), 0); +module_param(timeout, int, 0); +module_param(backplane, int, 0); +module_param(clockp, int, 0); +module_param(clockm, int, 0); MODULE_LICENSE("GPL"); static int __devinit com20020pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) @@ -68,15 +69,11 @@ if (pci_enable_device(pdev)) return -EIO; - dev = dev_alloc(device ? : "arc%d", &err); + dev = alloc_arcdev(device); if (!dev) - return err; - lp = dev->priv = kmalloc(sizeof(struct arcnet_local), GFP_KERNEL); - if (!lp) { - err = -ENOMEM; - goto out_dev; - } - memset(lp, 0, sizeof(struct arcnet_local)); + return -ENOMEM; + lp = dev->priv; + pci_set_drvdata(pdev, dev); // SOHARD needs PCI base addr 4 @@ -89,6 +86,13 @@ ioaddr = pci_resource_start(pdev, 2); } + if (!request_region(ioaddr, ARCNET_TOTAL_SIZE, "com20020-pci")) { + BUGMSG(D_INIT, "IO region %xh-%xh already allocated.\n", + ioaddr, ioaddr + ARCNET_TOTAL_SIZE - 1); + err = -EBUSY; + goto out_dev; + } + // Dummy access after Reset // ARCNET controller needs this access to detect bustype outb(0x00,ioaddr+1); @@ -105,12 +109,6 @@ lp->timeout = timeout; lp->hw.owner = THIS_MODULE; - if (!request_region(ioaddr, ARCNET_TOTAL_SIZE, "com20020-pci")) { - BUGMSG(D_INIT, "IO region %xh-%xh already allocated.\n", - ioaddr, ioaddr + ARCNET_TOTAL_SIZE - 1); - err = -EBUSY; - goto out_priv; - } if (ASTATUS() == 0xFF) { BUGMSG(D_NORMAL, "IO address %Xh was reported by PCI BIOS, " "but seems empty!\n", ioaddr); @@ -129,18 +127,18 @@ out_port: release_region(ioaddr, ARCNET_TOTAL_SIZE); -out_priv: - kfree(dev->priv); out_dev: - kfree(dev); + free_netdev(dev); return err; } static void __devexit com20020pci_remove(struct pci_dev *pdev) { struct net_device *dev = pci_get_drvdata(pdev); - com20020_remove(dev); + unregister_netdev(dev); + free_irq(dev->irq, dev); release_region(dev->base_addr, ARCNET_TOTAL_SIZE); + free_netdev(dev); } static struct pci_device_id com20020pci_id_table[] = { diff -Nru a/drivers/net/arcnet/com20020.c b/drivers/net/arcnet/com20020.c --- a/drivers/net/arcnet/com20020.c Thu Jan 22 18:59:24 2004 +++ b/drivers/net/arcnet/com20020.c Thu Jan 22 18:59:24 2004 @@ -172,11 +172,6 @@ dev->set_multicast_list = com20020_set_mc_list; - /* Fill in the fields of the device structure with generic - * values. - */ - arcdev_setup(dev); - if (!dev->dev_addr[0]) dev->dev_addr[0] = inb(ioaddr + 8); /* FIXME: do this some other way! */ @@ -221,7 +216,7 @@ lp->setup >> 1, clockrates[3 - ((lp->setup2 & 0xF0) >> 4) + ((lp->setup & 0x0F) >> 1)]); - if (!dev->init && register_netdev(dev)) { + if (register_netdev(dev)) { free_irq(dev->irq, dev); return -EIO; } @@ -332,19 +327,10 @@ } } -void com20020_remove(struct net_device *dev) -{ - unregister_netdev(dev); - free_irq(dev->irq, dev); - kfree(dev->priv); - free_netdev(dev); -} - #ifdef MODULE EXPORT_SYMBOL(com20020_check); EXPORT_SYMBOL(com20020_found); -EXPORT_SYMBOL(com20020_remove); MODULE_LICENSE("GPL"); diff -Nru a/drivers/net/arcnet/com90io.c b/drivers/net/arcnet/com90io.c --- a/drivers/net/arcnet/com90io.c Thu Jan 22 18:59:24 2004 +++ b/drivers/net/arcnet/com90io.c Thu Jan 22 18:59:24 2004 @@ -27,6 +27,7 @@ */ #include #include +#include #include #include #include @@ -234,6 +235,7 @@ { struct arcnet_local *lp; int ioaddr = dev->base_addr; + int err; /* Reserve the irq */ if (request_irq(dev->irq, &arcnet_interrupt, 0, "arcnet (COM90xx-IO)", dev)) { @@ -246,15 +248,6 @@ return -EBUSY; } - /* Initialize the rest of the device structure. */ - dev->priv = kmalloc(sizeof(struct arcnet_local), GFP_KERNEL); - if (!dev->priv) { - free_irq(dev->irq, dev); - release_region(dev->base_addr, ARCNET_TOTAL_SIZE); - return -ENOMEM; - } - memset(dev->priv, 0, sizeof(struct arcnet_local)); - lp = (struct arcnet_local *) (dev->priv); lp->card_name = "COM90xx I/O"; lp->hw.command = com90io_command; @@ -265,12 +258,6 @@ lp->hw.copy_to_card = com90io_copy_to_card; lp->hw.copy_from_card = com90io_copy_from_card; - /* - * Fill in the fields of the device structure with generic - * values. - */ - arcdev_setup(dev); - lp->config = (0x16 | IOMAPflag) & ~ENABLE16flag; SETCONF(); @@ -278,6 +265,14 @@ dev->dev_addr[0] = get_buffer_byte(dev, 1); + err = register_netdev(dev); + if (err) { + outb((inb(_CONFIG) & ~IOMAPflag), _CONFIG); + free_irq(dev->irq, dev); + release_region(dev->base_addr, ARCNET_TOTAL_SIZE); + return err; + } + BUGMSG(D_NORMAL, "COM90IO: station %02Xh found at %03lXh, IRQ %d.\n", dev->dev_addr[0], dev->base_addr, dev->irq); @@ -361,44 +356,67 @@ TIME("get_whole_buffer", count, get_whole_buffer(dev, bufnum * 512 + offset, count, buf)); } - -#ifdef MODULE - -static struct net_device *my_dev; - -/* Module parameters */ - static int io; /* use the insmod io= irq= shmem= options */ static int irq; -static char *device; /* use eg. device=arc1 to change name */ +static char device[9]; /* use eg. device=arc1 to change name */ -MODULE_PARM(io, "i"); -MODULE_PARM(irq, "i"); -MODULE_PARM(device, "s"); +module_param(io, int, 0); +module_param(irq, int, 0); +module_param_string(device, device, sizeof(device), 0); MODULE_LICENSE("GPL"); -int init_module(void) +#ifndef MODULE +static int __init com90io_setup(char *s) +{ + int ints[4]; + s = get_options(s, 4, ints); + if (!ints[0]) + return 0; + switch (ints[0]) { + default: /* ERROR */ + printk("com90io: Too many arguments.\n"); + case 2: /* IRQ */ + irq = ints[2]; + case 1: /* IO address */ + io = ints[1]; + } + if (*s) + snprintf(device, sizeof(device), "%s", s); + return 1; +} +__setup("com90io=", com90io_setup); +#endif + +static struct net_device *my_dev; + +static int __init com90io_init(void) { struct net_device *dev; int err; - dev = dev_alloc(device ? : "arc%d", &err); + dev = alloc_arcdev(device); if (!dev) - return err; + return -ENOMEM; + + SET_MODULE_OWNER(dev); dev->base_addr = io; dev->irq = irq; if (dev->irq == 2) dev->irq = 9; - if (com90io_probe(dev)) - return -EIO; + err = com90io_probe(dev); + + if (err) { + free_netdev(dev); + return err; + } my_dev = dev; return 0; } -void cleanup_module(void) +static void __exit com90io_exit(void) { struct net_device *dev = my_dev; int ioaddr = dev->base_addr; @@ -410,42 +428,8 @@ free_irq(dev->irq, dev); release_region(dev->base_addr, ARCNET_TOTAL_SIZE); - kfree(dev->priv); free_netdev(dev); } -#else - -static int __init com90io_setup(char *s) -{ - struct net_device *dev; - int ints[4]; - - s = get_options(s, 4, ints); - if (!ints[0]) - return 0; - dev = alloc_bootmem(sizeof(struct net_device)); - memset(dev, 0, sizeof(struct net_device)); - dev->init = com90io_probe; - - switch (ints[0]) { - default: /* ERROR */ - printk("com90io: Too many arguments.\n"); - case 2: /* IRQ */ - dev->irq = ints[2]; - case 1: /* IO address */ - dev->base_addr = ints[1]; - } - if (*s) - strncpy(dev->name, s, 9); - else - strcpy(dev->name, "arc%d"); - if (register_netdev(dev)) - printk(KERN_ERR "com90io: Cannot register arcnet device\n"); - - return 1; -} - -__setup("com90io=", com90io_setup); - -#endif /* MODULE */ +module_init(com90io_init) +module_exit(com90io_exit) diff -Nru a/drivers/net/arcnet/com90xx.c b/drivers/net/arcnet/com90xx.c --- a/drivers/net/arcnet/com90xx.c Thu Jan 22 18:59:26 2004 +++ b/drivers/net/arcnet/com90xx.c Thu Jan 22 18:59:26 2004 @@ -25,6 +25,7 @@ * ********************** */ #include +#include #include #include #include @@ -52,8 +53,7 @@ /* Internal function declarations */ -static int com90xx_found(struct net_device *dev, int ioaddr, int airq, - u_long shmem); +static int com90xx_found(int ioaddr, int airq, u_long shmem); static void com90xx_command(struct net_device *dev, int command); static int com90xx_status(struct net_device *dev); static void com90xx_setmask(struct net_device *dev, int mask); @@ -98,32 +98,43 @@ static int com90xx_skip_probe __initdata = 0; -static int __init com90xx_probe(struct net_device *dev) +/* Module parameters */ + +static int io; /* use the insmod io= irq= shmem= options */ +static int irq; +static int shmem; +static char device[9]; /* use eg. device=arc1 to change name */ + +module_param(io, int, 0); +module_param(irq, int, 0); +module_param(shmem, int, 0); +module_param_string(device, device, sizeof(device), 0); + +static void __init com90xx_probe(void) { - int count, status, ioaddr, numprint, airq, retval = -ENODEV, - openparen = 0; + int count, status, ioaddr, numprint, airq, openparen = 0; unsigned long airqmask; int ports[(0x3f0 - 0x200) / 16 + 1] = {0}; u_long shmems[(0xFF800 - 0xA0000) / 2048 + 1] = {0}; int numports, numshmems, *port; - u_long *shmem; + u_long *p; - if (!dev && com90xx_skip_probe) - return -ENODEV; + if (!io && !irq && !shmem && !*device && com90xx_skip_probe) + return; BUGLVL(D_NORMAL) printk(VERSION); /* set up the arrays where we'll store the possible probe addresses */ numports = numshmems = 0; - if (dev && dev->base_addr) - ports[numports++] = dev->base_addr; + if (io) + ports[numports++] = io; else for (count = 0x200; count <= 0x3f0; count += 16) ports[numports++] = count; - if (dev && dev->mem_start) - shmems[numshmems++] = dev->mem_start; + if (shmem) + shmems[numshmems++] = shmem; else for (count = 0xA0000; count <= 0xFF800; count += 2048) shmems[numshmems++] = count; @@ -143,22 +154,19 @@ ioaddr = *port; - if (check_region(*port, ARCNET_TOTAL_SIZE)) { + if (!request_region(*port, ARCNET_TOTAL_SIZE, "arcnet (90xx)")) { BUGMSG2(D_INIT_REASONS, "(check_region)\n"); BUGMSG2(D_INIT_REASONS, "S1: "); BUGLVL(D_INIT_REASONS) numprint = 0; - *port = ports[numports - 1]; - numports--; - port--; + *port-- = ports[--numports]; continue; } if (ASTATUS() == 0xFF) { BUGMSG2(D_INIT_REASONS, "(empty)\n"); BUGMSG2(D_INIT_REASONS, "S1: "); BUGLVL(D_INIT_REASONS) numprint = 0; - *port = ports[numports - 1]; - numports--; - port--; + release_region(*port, ARCNET_TOTAL_SIZE); + *port-- = ports[--numports]; continue; } inb(_RESET); /* begin resetting card */ @@ -171,14 +179,14 @@ if (!numports) { BUGMSG2(D_NORMAL, "S1: No ARCnet cards found.\n"); - return -ENODEV; + return; } /* Stage 2: we have now reset any possible ARCnet cards, so we can't * do anything until they finish. If D_INIT, print the list of * cards that are left. */ numprint = -1; - for (port = &ports[0]; port - ports < numports; port++) { + for (port = &ports[0]; port < ports + numports; port++) { numprint++; numprint %= 8; if (!numprint) { @@ -194,8 +202,8 @@ * 0xD1 byte in the right place, or are read-only. */ numprint = -1; - for (shmem = &shmems[0]; shmem - shmems < numshmems; shmem++) { - u_long ptr = *shmem; + for (p = &shmems[0]; p < shmems + numshmems; p++) { + u_long ptr = *p; numprint++; numprint %= 8; @@ -203,15 +211,13 @@ BUGMSG2(D_INIT, "\n"); BUGMSG2(D_INIT, "S3: "); } - BUGMSG2(D_INIT, "%lXh ", *shmem); + BUGMSG2(D_INIT, "%lXh ", *p); - if (check_mem_region(*shmem, BUFFER_SIZE)) { + if (!request_mem_region(*p, BUFFER_SIZE, "arcnet (90xx)")) { BUGMSG2(D_INIT_REASONS, "(check_mem_region)\n"); BUGMSG2(D_INIT_REASONS, "Stage 3: "); BUGLVL(D_INIT_REASONS) numprint = 0; - *shmem = shmems[numshmems - 1]; - numshmems--; - shmem--; + *p-- = shmems[--numshmems]; continue; } if (isa_readb(ptr) != TESTvalue) { @@ -219,9 +225,8 @@ isa_readb(ptr), TESTvalue); BUGMSG2(D_INIT_REASONS, "S3: "); BUGLVL(D_INIT_REASONS) numprint = 0; - *shmem = shmems[numshmems - 1]; - numshmems--; - shmem--; + release_mem_region(*p, BUFFER_SIZE); + *p-- = shmems[--numshmems]; continue; } /* By writing 0x42 to the TESTvalue location, we also make @@ -233,9 +238,8 @@ if (isa_readb(ptr) != 0x42) { BUGMSG2(D_INIT_REASONS, "(read only)\n"); BUGMSG2(D_INIT_REASONS, "S3: "); - *shmem = shmems[numshmems - 1]; - numshmems--; - shmem--; + release_mem_region(*p, BUFFER_SIZE); + *p-- = shmems[--numshmems]; continue; } BUGMSG2(D_INIT_REASONS, "\n"); @@ -246,20 +250,22 @@ if (!numshmems) { BUGMSG2(D_NORMAL, "S3: No ARCnet cards found.\n"); - return -ENODEV; + for (port = &ports[0]; port < ports + numports; port++) + release_region(*port, ARCNET_TOTAL_SIZE); + return; } /* Stage 4: something of a dummy, to report the shmems that are * still possible after stage 3. */ numprint = -1; - for (shmem = &shmems[0]; shmem - shmems < numshmems; shmem++) { + for (p = &shmems[0]; p < shmems + numshmems; p++) { numprint++; numprint %= 8; if (!numprint) { BUGMSG2(D_INIT, "\n"); BUGMSG2(D_INIT, "S4: "); } - BUGMSG2(D_INIT, "%lXh ", *shmem); + BUGMSG2(D_INIT, "%lXh ", *p); } BUGMSG2(D_INIT, "\n"); @@ -271,7 +277,8 @@ * after the first one is found. */ numprint = -1; - for (port = &ports[0]; port - ports < numports; port++) { + for (port = &ports[0]; port < ports + numports; port++) { + int found = 0; numprint++; numprint %= 8; if (!numprint) { @@ -288,9 +295,8 @@ BUGMSG2(D_INIT_REASONS, "(status=%Xh)\n", status); BUGMSG2(D_INIT_REASONS, "S5: "); BUGLVL(D_INIT_REASONS) numprint = 0; - *port = ports[numports - 1]; - numports--; - port--; + release_region(*port, ARCNET_TOTAL_SIZE); + *port-- = ports[--numports]; continue; } ACOMMAND(CFLAGScmd | RESETclear | CONFIGclear); @@ -300,15 +306,14 @@ status); BUGMSG2(D_INIT_REASONS, "S5: "); BUGLVL(D_INIT_REASONS) numprint = 0; - *port = ports[numports - 1]; - numports--; - port--; + release_region(*port, ARCNET_TOTAL_SIZE); + *port-- = ports[--numports]; continue; } /* skip this completely if an IRQ was given, because maybe * we're on a machine that locks during autoirq! */ - if (!dev || !dev->irq) { + if (!irq) { /* if we do this, we're sure to get an IRQ since the * card has just reset and the NORXflag is on until * we tell it to start receiving. @@ -323,13 +328,12 @@ BUGMSG2(D_INIT_REASONS, "(airq=%d)\n", airq); BUGMSG2(D_INIT_REASONS, "S5: "); BUGLVL(D_INIT_REASONS) numprint = 0; - *port = ports[numports - 1]; - numports--; - port--; + release_region(*port, ARCNET_TOTAL_SIZE); + *port-- = ports[--numports]; continue; } } else { - airq = dev->irq; + airq = irq; } BUGMSG2(D_INIT, "(%d,", airq); @@ -354,21 +358,20 @@ mdelay(RESETtime); #endif - for (shmem = &shmems[0]; shmem - shmems < numshmems; shmem++) { - u_long ptr = *shmem; + for (p = &shmems[0]; p < shmems + numshmems; p++) { + u_long ptr = *p; if (isa_readb(ptr) == TESTvalue) { /* found one */ - BUGMSG2(D_INIT, "%lXh)\n", *shmem); + BUGMSG2(D_INIT, "%lXh)\n", *p); openparen = 0; /* register the card */ - retval = com90xx_found(dev, *port, airq, *shmem); + if (com90xx_found(*port, airq, *p) == 0) + found = 1; numprint = -1; /* remove shmem from the list */ - *shmem = shmems[numshmems - 1]; - numshmems--; - + *p = shmems[--numshmems]; break; /* go to the next I/O port */ } else { BUGMSG2(D_INIT_REASONS, "%Xh-", isa_readb(ptr)); @@ -380,44 +383,39 @@ BUGLVL(D_INIT_REASONS) printk("S5: "); BUGLVL(D_INIT_REASONS) numprint = 0; } - *port = ports[numports - 1]; - numports--; - port--; + if (!found) + release_region(*port, ARCNET_TOTAL_SIZE); + *port-- = ports[--numports]; } BUGLVL(D_INIT_REASONS) printk("\n"); /* Now put back TESTvalue on all leftover shmems. */ - for (shmem = &shmems[0]; shmem - shmems < numshmems; shmem++) - isa_writeb(TESTvalue, *shmem); - - if (retval && dev && !numcards) - BUGMSG2(D_NORMAL, "S5: No ARCnet cards found.\n"); - return retval; + for (p = &shmems[0]; p < shmems + numshmems; p++) { + isa_writeb(TESTvalue, *p); + release_mem_region(*p, BUFFER_SIZE); + } } /* Set up the struct net_device associated with this card. Called after * probing succeeds. */ -static int __init com90xx_found(struct net_device *dev0, int ioaddr, int airq, - u_long shmem) +static int __init com90xx_found(int ioaddr, int airq, u_long shmem) { - struct net_device *dev = dev0; + struct net_device *dev = NULL; struct arcnet_local *lp; u_long first_mirror, last_mirror; - int mirror_size, err; + int mirror_size; - /* allocate struct net_device if we don't have one yet */ - if (!dev && !(dev = dev_alloc("arc%d", &err))) { + /* allocate struct net_device */ + dev = alloc_arcdev(device); + if (!dev) { BUGMSG2(D_NORMAL, "com90xx: Can't allocate device!\n"); - return err; - } - lp = dev->priv = kmalloc(sizeof(struct arcnet_local), GFP_KERNEL); - if (!lp) { - BUGMSG(D_NORMAL, "Can't allocate device data!\n"); - goto err_free_dev; + release_mem_region(shmem, BUFFER_SIZE); + return -ENOMEM; } + lp = dev->priv; /* find the real shared memory start/end points, including mirrors */ /* guess the actual size of one "memory mirror" - the number of @@ -442,8 +440,18 @@ dev->mem_start = first_mirror; dev->mem_end = last_mirror + MIRROR_SIZE - 1; + release_mem_region(shmem, BUFFER_SIZE); + if (!request_mem_region(dev->mem_start, dev->mem_end - dev->mem_start + 1, "arcnet (90xx)")) + goto err_free_dev; + + /* reserve the irq */ + if (request_irq(airq, &arcnet_interrupt, 0, "arcnet (90xx)", dev)) { + BUGMSG(D_NORMAL, "Can't get IRQ %d!\n", airq); + goto err_release_mem; + } + dev->irq = airq; + /* Initialize the rest of the device structure. */ - memset(lp, 0, sizeof(struct arcnet_local)); lp->card_name = "COM90xx"; lp->hw.command = com90xx_command; lp->hw.status = com90xx_status; @@ -455,24 +463,12 @@ lp->mem_start = ioremap(dev->mem_start, dev->mem_end - dev->mem_start + 1); if (!lp->mem_start) { BUGMSG(D_NORMAL, "Can't remap device memory!\n"); - goto err_free_dev_priv; + goto err_free_irq; } - /* Fill in the fields of the device structure with generic values. */ - arcdev_setup(dev); /* get and check the station ID from offset 1 in shmem */ dev->dev_addr[0] = readb(lp->mem_start + 1); - /* reserve the irq */ - if (request_irq(airq, &arcnet_interrupt, 0, "arcnet (90xx)", dev)) { - BUGMSG(D_NORMAL, "Can't get IRQ %d!\n", airq); - goto err_unmap; - } - dev->irq = airq; - - /* reserve the I/O and memory regions - guaranteed to work by check_region */ - request_region(ioaddr, ARCNET_TOTAL_SIZE, "arcnet (90xx)"); - request_mem_region(dev->mem_start, dev->mem_end - dev->mem_start + 1, "arcnet (90xx)"); dev->base_addr = ioaddr; BUGMSG(D_NORMAL, "COM90xx station %02Xh found at %03lXh, IRQ %d, " @@ -481,23 +477,20 @@ dev->base_addr, dev->irq, dev->mem_start, (dev->mem_end - dev->mem_start + 1) / mirror_size, mirror_size); - if (!dev0 && register_netdev(dev)) - goto err_release; + if (register_netdev(dev)) + goto err_unmap; cards[numcards++] = dev; return 0; - err_release: +err_unmap: + iounmap(lp->mem_start); +err_free_irq: free_irq(dev->irq, dev); - release_region(dev->base_addr, ARCNET_TOTAL_SIZE); +err_release_mem: release_mem_region(dev->mem_start, dev->mem_end - dev->mem_start + 1); - err_unmap: - iounmap(lp->mem_start); - err_free_dev_priv: - kfree(dev->priv); - err_free_dev: - if (!dev0) - kfree(dev); +err_free_dev: + free_netdev(dev); return -EIO; } @@ -587,37 +580,13 @@ } -/* Module parameters */ - -static int io; /* use the insmod io= irq= shmem= options */ -static int irq; -static int shmem; -static char *device; /* use eg. device=arc1 to change name */ - -MODULE_PARM(io, "i"); -MODULE_PARM(irq, "i"); -MODULE_PARM(shmem, "i"); -MODULE_PARM(device, "s"); MODULE_LICENSE("GPL"); static int __init com90xx_init(void) { - struct net_device *dev; - int err; - - if (io || irq || shmem || device) { - dev = dev_alloc(device ? : "arc%d", &err); - if (!dev) - return err; - dev->base_addr = io; - dev->irq = irq; - if (dev->irq == 2) - dev->irq = 9; - dev->mem_start = shmem; - com90xx_probe(dev); - } else - com90xx_probe(NULL); - + if (irq == 2) + irq = 9; + com90xx_probe(); if (!numcards) return -EIO; return 0; @@ -638,7 +607,6 @@ iounmap(lp->mem_start); release_region(dev->base_addr, ARCNET_TOTAL_SIZE); release_mem_region(dev->mem_start, dev->mem_end - dev->mem_start + 1); - kfree(dev->priv); free_netdev(dev); } } @@ -669,9 +637,7 @@ } if (*s) - strncpy(device, s, 9); - else - strcpy(device, "arc%d"); + snprintf(device, sizeof(device), "%s", s); return 1; } diff -Nru a/drivers/net/ariadne.c b/drivers/net/ariadne.c --- a/drivers/net/ariadne.c Thu Jan 22 18:59:26 2004 +++ b/drivers/net/ariadne.c Thu Jan 22 18:59:26 2004 @@ -168,7 +168,7 @@ continue; } - dev = init_etherdev(NULL, sizeof(struct ariadne_private)); + dev = alloc_etherdev(sizeof(struct ariadne_private)); if (dev == NULL) { release_resource(r1); @@ -205,11 +205,17 @@ dev->get_stats = &ariadne_get_stats; dev->set_multicast_list = &set_multicast_list; + res = register_netdev(dev); + if (res) { + release_resource(r1); + release_resource(r2); + free_netdev(dev); + break; + } #ifdef MODULE priv->next_module = root_ariadne_dev; root_ariadne_dev = priv; #endif - res = 0; } return res; } diff -Nru a/drivers/net/arm/am79c961a.c b/drivers/net/arm/am79c961a.c --- a/drivers/net/arm/am79c961a.c Thu Jan 22 18:59:26 2004 +++ b/drivers/net/arm/am79c961a.c Thu Jan 22 18:59:26 2004 @@ -672,6 +672,10 @@ dev->base_addr = 0x220; dev->irq = IRQ_EBSA110_ETHERNET; + ret = -ENODEV; + if (!request_region(dev->base_addr, 0x18, dev->name)) + goto nodev; + /* * Reset the device. */ @@ -682,14 +686,10 @@ * Check the manufacturer part of the * ether address. */ - ret = -ENODEV; if (inb(dev->base_addr) != 0x08 || inb(dev->base_addr + 2) != 0x00 || inb(dev->base_addr + 4) != 0x2b) - goto nodev; - - if (!request_region(dev->base_addr, 0x18, dev->name)) - goto nodev; + goto release; am79c961_banner(); printk(KERN_INFO "%s: ether address ", dev->name); @@ -722,7 +722,7 @@ release: release_region(dev->base_addr, 0x18); nodev: - kfree(dev); + free_netdev(dev); out: return ret; } diff -Nru a/drivers/net/arm/ether00.c b/drivers/net/arm/ether00.c --- a/drivers/net/arm/ether00.c Thu Jan 22 18:59:27 2004 +++ b/drivers/net/arm/ether00.c Thu Jan 22 18:59:27 2004 @@ -923,8 +923,6 @@ result = -ENOMEM; goto out_release; } - memset(dev,0,sizeof(struct net_device)); - memset(dev->priv, 0, sizeof(struct net_priv)); priv = dev->priv; priv->tq_memupdate.routine=ether00_mem_update; @@ -966,7 +964,7 @@ out_unmap: iounmap(map_addr); out_kfree: - kfree(dev); + free_netdev(dev); out_release: release_mem_region(dev_info->base_addr, MAC_REG_SIZE); return result; diff -Nru a/drivers/net/arm/ether1.c b/drivers/net/arm/ether1.c --- a/drivers/net/arm/ether1.c Thu Jan 22 18:59:25 2004 +++ b/drivers/net/arm/ether1.c Thu Jan 22 18:59:25 2004 @@ -1068,7 +1068,7 @@ release: release_region(dev->base_addr, 16); release_region(dev->base_addr + 0x800, 4096); - kfree(dev); + free_netdev(dev); out: return ret; } diff -Nru a/drivers/net/arm/ether3.c b/drivers/net/arm/ether3.c --- a/drivers/net/arm/ether3.c Thu Jan 22 18:59:27 2004 +++ b/drivers/net/arm/ether3.c Thu Jan 22 18:59:27 2004 @@ -908,7 +908,7 @@ failed: release_region(dev->base_addr, 128); free: - kfree(dev); + free_netdev(dev); out: return ret; } diff -Nru a/drivers/net/arm/etherh.c b/drivers/net/arm/etherh.c --- a/drivers/net/arm/etherh.c Thu Jan 22 18:59:26 2004 +++ b/drivers/net/arm/etherh.c Thu Jan 22 18:59:26 2004 @@ -551,15 +551,12 @@ etherh_banner(); - dev = alloc_etherdev(sizeof(struct etherh_priv)); + dev = alloc_ei_netdev(); if (!dev) { ret = -ENOMEM; goto out; } - /* - * alloc_etherdev allocs and zeros dev->priv - */ eh = dev->priv; spin_lock_init(&eh->eidev.page_lock); @@ -622,21 +619,12 @@ goto free; } - if (ethdev_init(dev)) { - ret = -ENODEV; - goto release; - } - /* * If we're in the NIC slot, make sure the IRQ is enabled */ if (dev->irq == 11) etherh_set_ctrl(eh, ETHERH_CP_IE); - /* - * Unfortunately, ethdev_init eventually calls - * ether_setup, which re-writes dev->flags. - */ switch (ec->cid.product) { case PROD_ANT_ETHERM: dev_type = "ANT EtherM"; @@ -705,7 +693,7 @@ release: release_region(dev->base_addr, 16); free: - kfree(dev); + free_netdev(dev); out: return ret; } diff -Nru a/drivers/net/at1700.c b/drivers/net/at1700.c --- a/drivers/net/at1700.c Thu Jan 22 18:59:24 2004 +++ b/drivers/net/at1700.c Thu Jan 22 18:59:24 2004 @@ -81,12 +81,12 @@ */ #ifndef CONFIG_X86_PC9800 -static int at1700_probe_list[] __initdata = { +static unsigned at1700_probe_list[] __initdata = { 0x260, 0x280, 0x2a0, 0x240, 0x340, 0x320, 0x380, 0x300, 0 }; #else /* CONFIG_X86_PC9800 */ -static int at1700_probe_list[] __initdata = { +static unsigned at1700_probe_list[] __initdata = { 0x1d6, 0x1d8, 0x1da, 0x1d4, 0xd4, 0xd2, 0xd8, 0xd0, 0 }; @@ -196,8 +196,6 @@ /* Index to functions, as function prototypes. */ -extern int at1700_probe(struct net_device *dev); - static int at1700_probe1(struct net_device *dev, int ioaddr); static int read_eeprom(long ioaddr, int location); static int net_open(struct net_device *dev); @@ -232,24 +230,78 @@ (detachable devices only). */ -int __init at1700_probe(struct net_device *dev) +#ifndef CONFIG_X86_PC9800 +static int io = 0x260; +#else +static int io = 0xd0; +#endif + +static int irq; + +static void cleanup_card(struct net_device *dev) { - int i; - int base_addr = dev->base_addr; +#ifdef CONFIG_MCA + struct net_local *lp = dev->priv; + if (lp->mca_slot) + mca_mark_as_unused(lp->mca_slot); +#endif + free_irq(dev->irq, NULL); +#ifndef CONFIG_X86_PC9800 + release_region(dev->base_addr, AT1700_IO_EXTENT); +#else + { + int i; + for (i = 0; i < 0x2000; i += 0x200) + release_region(dev->base_addr + i, 2); + } +#endif +} + +struct net_device * __init at1700_probe(int unit) +{ + struct net_device *dev = alloc_etherdev(sizeof(struct net_local)); + unsigned *port; + int err = 0; + + if (!dev) + return ERR_PTR(-ENODEV); + + if (unit >= 0) { + sprintf(dev->name, "eth%d", unit); + netdev_boot_setup_check(dev); + io = dev->base_addr; + irq = dev->irq; + } else { + dev->base_addr = io; + dev->irq = irq; + } SET_MODULE_OWNER(dev); - if (base_addr > 0x1ff) /* Check a single specified location. */ - return at1700_probe1(dev, base_addr); - else if (base_addr != 0) /* Don't probe at all. */ - return -ENXIO; - - for (i = 0; at1700_probe_list[i]; i++) { - int ioaddr = at1700_probe_list[i]; - if (at1700_probe1(dev, ioaddr) == 0) - return 0; + if (io > 0x1ff) { /* Check a single specified location. */ + err = at1700_probe1(dev, io); + } else if (io != 0) { /* Don't probe at all. */ + err = -ENXIO; + } else { + for (port = at1700_probe_list; *port; port++) { + if (at1700_probe1(dev, *port) == 0) + break; + dev->irq = irq; + } + if (!*port) + err = -ENODEV; } - return -ENODEV; + if (err) + goto out; + err = register_netdev(dev); + if (err) + goto out1; + return dev; +out1: + cleanup_card(dev); +out: + free_netdev(dev); + return ERR_PTR(err); } /* The Fujitsu datasheet suggests that the NIC be probed for by checking its @@ -267,7 +319,7 @@ char at1700_irqmap[8] = {3, 4, 5, 9, 10, 11, 14, 15}; unsigned int i, irq, is_fmv18x = 0, is_at1700 = 0; int slot, ret = -ENODEV; - struct net_local *lp; + struct net_local *lp = dev->priv; #ifndef CONFIG_X86_PC9800 if (!request_region(ioaddr, AT1700_IO_EXTENT, dev->name)) @@ -284,9 +336,10 @@ } #endif - /* Resetting the chip doesn't reset the ISA interface, so don't bother. - That means we have to be careful with the register values we probe for. - */ + /* Resetting the chip doesn't reset the ISA interface, so don't bother. + That means we have to be careful with the register values we probe + for. + */ #ifdef notdef printk("at1700 probe at %#x, eeprom is %4.4x %4.4x %4.4x ctrl %4.4x.\n", ioaddr, read_eeprom(ioaddr, 4), read_eeprom(ioaddr, 5), @@ -331,15 +384,13 @@ break; /* probing for a card at a particular IO/IRQ */ - if (dev && - ((dev->irq && dev->irq != irq) || - (dev->base_addr && dev->base_addr != ioaddr))) { + if ((dev->irq && dev->irq != irq) || + (dev->base_addr && dev->base_addr != ioaddr)) { slot++; /* probing next slot */ continue; } - if (dev) - dev->irq = irq; + dev->irq = irq; /* claim the slot */ mca_set_adapter_name( slot, at1720_mca_adapters[j].name ); @@ -476,13 +527,7 @@ if (net_debug) printk(version); - /* Initialize the device structure. */ - dev->priv = kmalloc(sizeof(struct net_local), GFP_KERNEL); - if (dev->priv == NULL) { - ret = -ENOMEM; - goto err_out; - } - memset(dev->priv, 0, sizeof(struct net_local)); + memset(lp, 0, sizeof(struct net_local)); dev->open = net_open; dev->stop = net_close; @@ -492,11 +537,7 @@ dev->tx_timeout = net_tx_timeout; dev->watchdog_timeo = TX_TIMEOUT; - lp = (struct net_local *)dev->priv; - lp->lock = SPIN_LOCK_UNLOCKED; - - /* Fill in the fields of 'dev' with ethernet-generic values. */ - ether_setup(dev); + spin_lock_init(&lp->lock); lp->jumpered = is_fmv18x; lp->mca_slot = slot; @@ -505,14 +546,11 @@ if (ret) { printk (" AT1700 at %#3x is unusable due to a conflict on" "IRQ %d.\n", ioaddr, irq); - goto err_out_priv; + goto err_out; } return 0; -err_out_priv: - kfree(dev->priv); - dev->priv = NULL; err_out: #ifndef CONFIG_X86_PC9800 release_region(ioaddr, AT1700_IO_EXTENT); @@ -940,14 +978,7 @@ } #ifdef MODULE -static struct net_device dev_at1700; -#ifndef CONFIG_X86_PC9800 -static int io = 0x260; -#else -static int io = 0xd0; -#endif - -static int irq; +static struct net_device *dev_at1700; MODULE_PARM(io, "i"); MODULE_PARM(irq, "i"); @@ -960,41 +991,18 @@ { if (io == 0) printk("at1700: You should not use auto-probing with insmod!\n"); - dev_at1700.base_addr = io; - dev_at1700.irq = irq; - dev_at1700.init = at1700_probe; - if (register_netdev(&dev_at1700) != 0) { - printk("at1700: register_netdev() returned non-zero.\n"); - return -EIO; - } + dev_at1700 = at1700_probe(-1); + if (IS_ERR(dev_at1700)) + return PTR_ERR(dev_at1700); return 0; } void cleanup_module(void) { -#ifdef CONFIG_MCA - struct net_local *lp = dev_at1700.priv; - if(lp->mca_slot) - { - mca_mark_as_unused(lp->mca_slot); - } -#endif - unregister_netdev(&dev_at1700); - kfree(dev_at1700.priv); - dev_at1700.priv = NULL; - - /* If we don't do this, we can't re-insmod it later. */ - free_irq(dev_at1700.irq, NULL); -#ifndef CONFIG_X86_PC9800 - release_region(dev_at1700.base_addr, AT1700_IO_EXTENT); -#else - { - int i; - for (i = 0; i < 0x2000; i += 0x200) - release_region(dev_at1700.base_addr + i, 2); - } -#endif + unregister_netdev(dev_at1700); + cleanup_card(dev_at1700); + free_netdev(dev_at1700); } #endif /* MODULE */ MODULE_LICENSE("GPL"); diff -Nru a/drivers/net/atari_bionet.c b/drivers/net/atari_bionet.c --- a/drivers/net/atari_bionet.c Thu Jan 22 18:59:25 2004 +++ b/drivers/net/atari_bionet.c Thu Jan 22 18:59:25 2004 @@ -148,8 +148,6 @@ /* Index to functions, as function prototypes. */ -extern int bionet_probe(struct net_device *dev); - static int bionet_open(struct net_device *dev); static int bionet_send_packet(struct sk_buff *skb, struct net_device *dev); static void bionet_poll_rx(struct net_device *); @@ -321,15 +319,26 @@ /* Check for a network adaptor of this type, and return '0' if one exists. */ -int __init -bionet_probe(struct net_device *dev){ +struct net_device * __init bionet_probe(int unit) +{ + struct net_device *dev; unsigned char station_addr[6]; static unsigned version_printed; static int no_more_found; /* avoid "Probing for..." printed 4 times */ int i; + int err; if (!MACH_IS_ATARI || no_more_found) - return -ENODEV; + return ERR_PTR(-ENODEV); + + dev = alloc_etherdev(sizeof(struct net_local)); + if (!dev) + return ERR_PTR(-ENOMEM); + if (unit >= 0) { + sprintf(dev->name, "eth%d", unit); + netdev_boot_setup_check(dev); + } + SET_MODULE_OWNER(dev); printk("Probing for BioNet 100 Adapter...\n"); @@ -347,11 +356,10 @@ || station_addr[2] != 'O' ) { no_more_found = 1; printk( "No BioNet 100 found.\n" ); - return -ENODEV; + free_netdev(dev); + return ERR_PTR(-ENODEV); } - SET_MODULE_OWNER(dev); - if (bionet_debug > 0 && version_printed++ == 0) printk(version); @@ -369,12 +377,6 @@ nic_packet, phys_nic_packet ); } - if (dev->priv == NULL) - dev->priv = kmalloc(sizeof(struct net_local), GFP_KERNEL); - if (!dev->priv) - return -ENOMEM; - memset(dev->priv, 0, sizeof(struct net_local)); - dev->open = bionet_open; dev->stop = bionet_close; dev->hard_start_xmit = bionet_send_packet; @@ -390,8 +392,11 @@ #endif dev->dev_addr[i] = station_addr[i]; } - ether_setup(dev); - return 0; + err = register_netdev(dev); + if (!err) + return dev; + free_netdev(dev); + return ERR_PTR(err); } /* Open/initialize the board. This is called (in the current kernel) @@ -640,25 +645,20 @@ #ifdef MODULE -static struct net_device bio_dev; - -int -init_module(void) { - int err; +static struct net_device *bio_dev; - bio_dev.init = bionet_probe; - if ((err = register_netdev(&bio_dev))) { - if (err == -EEXIST) { - printk("BIONET: devices already present. Module not loaded.\n"); - } - return err; - } +int init_module(void) +{ + bio_dev = bionet_probe(-1); + if (IS_ERR(bio_dev)) + return PTR_ERR(bio_dev); return 0; } -void -cleanup_module(void) { - unregister_netdev(&bio_dev); +void cleanup_module(void) +{ + unregister_netdev(bio_dev); + free_netdev(bio_dev); } #endif /* MODULE */ diff -Nru a/drivers/net/atari_pamsnet.c b/drivers/net/atari_pamsnet.c --- a/drivers/net/atari_pamsnet.c Thu Jan 22 18:59:24 2004 +++ b/drivers/net/atari_pamsnet.c Thu Jan 22 18:59:24 2004 @@ -110,8 +110,6 @@ #undef READ #undef WRITE -extern struct net_device *init_etherdev(struct net_device *dev, int sizeof_private); - /* use 0 for production, 1 for verification, >2 for debug */ #ifndef NET_DEBUG @@ -158,8 +156,6 @@ static int get_status (void); static int calc_received (void *start_address); -extern int pamsnet_probe(struct net_device *dev); - static int pamsnet_open(struct net_device *dev); static int pamsnet_send_packet(struct sk_buff *skb, struct net_device *dev); static void pamsnet_poll_rx(struct net_device *); @@ -562,12 +558,12 @@ /* Check for a network adaptor of this type, and return '0' if one exists. */ -int __init -pamsnet_probe (dev) - struct net_device *dev; +struct net_device * __init pamsnet_probe (int unit) { + struct net_device *dev; int i; HADDR *hwaddr; + int err; unsigned char station_addr[6]; static unsigned version_printed; @@ -575,12 +571,18 @@ static int no_more_found; if (no_more_found) - return -ENODEV; + return ERR_PTR(-ENODEV); + no_more_found = 1; + dev = alloc_etherdev(sizeof(struct net_local)); + if (!dev) + return ERR_PTR(-ENOMEM); + if (unit >= 0) { + sprintf(dev->name, "eth%d", unit); + netdev_boot_setup_check(dev); + } SET_MODULE_OWNER(dev); - no_more_found = 1; - printk("Probing for PAM's Net/GK Adapter...\n"); /* Allocate the DMA buffer here since we need it for probing! */ @@ -618,11 +620,12 @@ ENABLE_IRQ(); stdma_release(); - if (lance_target < 0) + if (lance_target < 0) { printk("No PAM's Net/GK found.\n"); + free_netdev(dev); + return ERR_PTR(-ENODEV); + } - if ((dev == NULL) || (lance_target < 0)) - return -ENODEV; if (pamsnet_debug > 0 && version_printed++ == 0) printk(version); @@ -632,12 +635,6 @@ station_addr[3], station_addr[4], station_addr[5]); /* Initialize the device structure. */ - if (dev->priv == NULL) - dev->priv = kmalloc(sizeof(struct net_local), GFP_KERNEL); - if (!dev->priv) - return -ENOMEM; - memset(dev->priv, 0, sizeof(struct net_local)); - dev->open = pamsnet_open; dev->stop = pamsnet_close; dev->hard_start_xmit = pamsnet_send_packet; @@ -653,9 +650,12 @@ #endif dev->dev_addr[i] = station_addr[i]; } - ether_setup(dev); + err = register_netdev(dev); + if (!err) + return dev; - return(0); + free_netdev(dev); + return ERR_PTR(err); } /* Open/initialize the board. This is called (in the current kernel) @@ -866,25 +866,20 @@ #ifdef MODULE -static struct net_device pam_dev; - -int -init_module(void) { - int err; +static struct net_device *pam_dev; - pam_dev.init = pamsnet_probe; - if ((err = register_netdev(&pam_dev))) { - if (err == -EEXIST) { - printk("PAM's Net/GK: devices already present. Module not loaded.\n"); - } - return err; - } +int init_module(void) +{ + pam_dev = pamsnet_probe(-1); + if (IS_ERR(pam_dev)) + return PTR_ERR(pam_dev); return 0; } -void -cleanup_module(void) { - unregister_netdev(&pam_dev); +void cleanup_module(void) +{ + unregister_netdev(pam_dev); + free_netdev(pam_dev); } #endif /* MODULE */ diff -Nru a/drivers/net/atarilance.c b/drivers/net/atarilance.c --- a/drivers/net/atarilance.c Thu Jan 22 18:59:24 2004 +++ b/drivers/net/atarilance.c Thu Jan 22 18:59:24 2004 @@ -371,26 +371,39 @@ } -int __init atarilance_probe( struct net_device *dev ) -{ +struct net_device * __init atarilance_probe(int unit) +{ int i; static int found; - - SET_MODULE_OWNER(dev); + struct net_device *dev; + int err = -ENODEV; if (!MACH_IS_ATARI || found) /* Assume there's only one board possible... That seems true, since * the Riebl/PAM board's address cannot be changed. */ - return( ENODEV ); + return ERR_PTR(-ENODEV); + + dev = alloc_etherdev(sizeof(struct lance_private)); + if (!dev) + return ERR_PTR(-ENOMEM); + if (unit >= 0) { + sprintf(dev->name, "eth%d", unit); + netdev_boot_setup_check(dev); + } + SET_MODULE_OWNER(dev); for( i = 0; i < N_LANCE_ADDR; ++i ) { if (lance_probe1( dev, &lance_addr_list[i] )) { found = 1; - return( 0 ); + err = register_netdev(dev); + if (!err) + return dev; + free_irq(dev->irq, dev); + break; } } - - return( ENODEV ); + free_netdev(dev); + return ERR_PTR(err); } @@ -511,12 +524,6 @@ return( 0 ); probe_ok: - init_etherdev( dev, sizeof(struct lance_private) ); - if (!dev->priv) { - dev->priv = kmalloc( sizeof(struct lance_private), GFP_KERNEL ); - if (!dev->priv) - return 0; - } lp = (struct lance_private *)dev->priv; MEM = (struct lance_memory *)memaddr; IO = lp->iobase = (struct lance_ioreg *)ioaddr; @@ -1171,26 +1178,21 @@ #ifdef MODULE -static struct net_device atarilance_dev; +static struct net_device *atarilance_dev; int init_module(void) - -{ int err; - - atarilance_dev.init = atarilance_probe; - if ((err = register_netdev( &atarilance_dev ))) { - if (err == -EIO) { - printk( "No Atari Lance board found. Module not loaded.\n"); - } - return( err ); - } - return( 0 ); +{ + atarilance_dev = atarilance_probe(-1); + if (IS_ERR(atarilance_dev)) + return PTR_ERR(atarilance_dev); + return 0; } void cleanup_module(void) - { - unregister_netdev( &atarilance_dev ); + unregister_netdev(atarilance_dev); + free_irq(atarilance_dev->irq, atarilance_dev); + free_netdev(atarilance_dev); } #endif /* MODULE */ diff -Nru a/drivers/net/atp.c b/drivers/net/atp.c --- a/drivers/net/atp.c Thu Jan 22 18:59:27 2004 +++ b/drivers/net/atp.c Thu Jan 22 18:59:27 2004 @@ -195,7 +195,7 @@ /* Index to functions, as function prototypes. */ -static int atp_probe1(struct net_device *dev, long ioaddr); +static int atp_probe1(long ioaddr); static void get_node_ID(struct net_device *dev); static unsigned short eeprom_op(long ioaddr, unsigned int cmd); static int net_open(struct net_device *dev); @@ -224,13 +224,13 @@ FIXME: we should use the parport layer for this */ -static int __init atp_init(struct net_device *dev) +static int __init atp_init(void) { int *port, ports[] = {0x378, 0x278, 0x3bc, 0}; - int base_addr = dev ? dev->base_addr : io[0]; + int base_addr = io[0]; if (base_addr > 0x1ff) /* Check a single specified location. */ - return atp_probe1(dev, base_addr); + return atp_probe1(base_addr); else if (base_addr == 1) /* Don't probe at all. */ return -ENXIO; @@ -239,17 +239,19 @@ outb(0x57, ioaddr + PAR_DATA); if (inb(ioaddr + PAR_DATA) != 0x57) continue; - if (atp_probe1(dev, ioaddr) == 0) + if (atp_probe1(ioaddr) == 0) return 0; } return -ENODEV; } -static int __init atp_probe1(struct net_device *dev, long ioaddr) +static int __init atp_probe1(long ioaddr) { + struct net_device *dev = NULL; struct net_local *lp; int saved_ctrl_reg, status, i; + int res; outb(0xff, ioaddr + PAR_DATA); /* Save the original value of the Control register, in case we guessed @@ -296,7 +298,7 @@ return -ENODEV; } - dev = init_etherdev(dev, sizeof(struct net_local)); + dev = alloc_etherdev(sizeof(struct net_local)); if (!dev) return -ENOMEM; SET_MODULE_OWNER(dev); @@ -331,24 +333,13 @@ dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]); /* Reset the ethernet hardware and activate the printer pass-through. */ - write_reg_high(ioaddr, CMR1, CMR1h_RESET | CMR1h_MUX); - - /* Initialize the device structure. */ - ether_setup(dev); - if (dev->priv == NULL) - dev->priv = kmalloc(sizeof(struct net_local), GFP_KERNEL); - if (dev->priv == NULL) - return -ENOMEM; - memset(dev->priv, 0, sizeof(struct net_local)); + write_reg_high(ioaddr, CMR1, CMR1h_RESET | CMR1h_MUX); lp = (struct net_local *)dev->priv; lp->chip_type = RTL8002; lp->addr_mode = CMR2h_Normal; spin_lock_init(&lp->lock); - lp->next_module = root_atp_dev; - root_atp_dev = dev; - /* For the ATP adapter the "if_port" is really the data transfer mode. */ if (xcvr[0]) dev->if_port = xcvr[0]; @@ -366,6 +357,15 @@ dev->tx_timeout = tx_timeout; dev->watchdog_timeo = TX_TIMEOUT; + res = register_netdev(dev); + if (res) { + free_netdev(dev); + return res; + } + + lp->next_module = root_atp_dev; + root_atp_dev = dev; + return 0; } @@ -933,7 +933,7 @@ static int __init atp_init_module(void) { if (debug) /* Emit version even if no cards detected. */ printk(KERN_INFO "%s" KERN_INFO "%s", versionA, versionB); - return atp_init(NULL); + return atp_init(); } static void __exit atp_cleanup_module(void) { diff -Nru a/drivers/net/au1000_eth.c b/drivers/net/au1000_eth.c --- a/drivers/net/au1000_eth.c Thu Jan 22 18:59:25 2004 +++ b/drivers/net/au1000_eth.c Thu Jan 22 18:59:25 2004 @@ -56,7 +56,7 @@ static void dma_free(void *, size_t); static void hard_stop(struct net_device *); static void enable_rx_tx(struct net_device *dev); -static int __init au1000_probe1(struct net_device *, long, int, int); +static int __init au1000_probe1(long, int, int); static int au1000_init(struct net_device *); static int au1000_open(struct net_device *); static int au1000_close(struct net_device *); @@ -644,17 +644,17 @@ } // check for valid entries, au1100 only has one entry if (base_addr && irq) { - if (au1000_probe1(NULL, base_addr, irq, i) != 0) { + if (au1000_probe1(base_addr, irq, i) != 0) return -ENODEV; - } } } return 0; } static int __init -au1000_probe1(struct net_device *dev, long ioaddr, int irq, int port_num) +au1000_probe1(long ioaddr, int irq, int port_num) { + struct net_device *dev; static unsigned version_printed = 0; struct au1000_private *aup = NULL; int i, retval = 0; @@ -668,15 +668,16 @@ if (version_printed++ == 0) printk(version); - if (!dev) - dev = init_etherdev(NULL, sizeof(struct au1000_private)); + retval = -ENOMEM; + dev = alloc_etherdev(sizeof(struct au1000_private)); if (!dev) { - printk (KERN_ERR "au1000 eth: init_etherdev failed\n"); - release_region(ioaddr, MAC_IOSIZE); - return -ENODEV; + printk (KERN_ERR "au1000 eth: alloc_etherdev failed\n"); + goto out; } + SET_MODULE_OWNER(dev); + printk("%s: Au1xxx ethernet found at 0x%lx, irq %d\n", dev->name, ioaddr, irq); @@ -685,10 +686,8 @@ /* Allocate the data buffers */ aup->vaddr = (u32)dma_alloc(MAX_BUF_SIZE * (NUM_TX_BUFFS+NUM_RX_BUFFS), &aup->dma_addr); - if (!aup->vaddr) { - retval = -ENOMEM; - goto free_region; - } + if (!aup->vaddr) + goto out1; /* aup->mac is the base address of the MAC's registers */ aup->mac = (volatile mac_reg_t *)((unsigned long)ioaddr); @@ -749,10 +748,11 @@ MAC_EN_RESET2 | MAC_EN_CLOCK_ENABLE; au_sync_delay(2); - if (mii_probe(dev) != 0) { - goto free_region; - } + retval = mii_probe(dev); + if (retval) + goto out2; + retval = -EINVAL; pDBfree = NULL; /* setup the data buffer descriptors and attach a buffer to each one */ pDB = aup->db; @@ -767,13 +767,13 @@ for (i=0; irx_dma_ring[i]->buff_stat = (unsigned)pDB->dma_addr; aup->rx_db_inuse[i] = pDB; } for (i=0; itx_dma_ring[i]->buff_stat = (unsigned)pDB->dma_addr; aup->tx_dma_ring[i]->len = 0; aup->tx_db_inuse[i] = pDB; @@ -792,26 +792,25 @@ dev->tx_timeout = au1000_tx_timeout; dev->watchdog_timeo = ETH_TX_TIMEOUT; - - /* Fill in the fields of the device structure with ethernet values. */ - ether_setup(dev); - /* * The boot code uses the ethernet controller, so reset it to start * fresh. au1000_init() expects that the device is in reset state. */ reset_mac(dev); + + retval = register_netdev(dev); + if (retval) + goto out2; return 0; -free_region: +out2: + dma_free(aup->vaddr, MAX_BUF_SIZE * (NUM_TX_BUFFS+NUM_RX_BUFFS)); +out1: + free_netdev(dev); +out: release_region(PHYSADDR(ioaddr), MAC_IOSIZE); - unregister_netdev(dev); - if (aup->vaddr) - dma_free((void *)aup->vaddr, - MAX_BUF_SIZE * (NUM_TX_BUFFS+NUM_RX_BUFFS)); printk(KERN_ERR "%s: au1000_probe1 failed. Returns %d\n", dev->name, retval); - free_netdev(dev); return retval; } @@ -933,15 +932,12 @@ int retval; struct au1000_private *aup = (struct au1000_private *) dev->priv; - MOD_INC_USE_COUNT; - if (au1000_debug > 4) printk("%s: open: dev=%p\n", dev->name, dev); if ((retval = au1000_init(dev))) { printk(KERN_ERR "%s: error in au1000_init\n", dev->name); free_irq(dev->irq, dev); - MOD_DEC_USE_COUNT; return retval; } netif_start_queue(dev); @@ -950,7 +946,6 @@ dev->name, dev))) { printk(KERN_ERR "%s: unable to get IRQ %d\n", dev->name, dev->irq); - MOD_DEC_USE_COUNT; return retval; } @@ -984,8 +979,6 @@ spin_unlock_irqrestore(&aup->lock, flags); reset_mac(dev); - kfree(dev); - MOD_DEC_USE_COUNT; return 0; } diff -Nru a/drivers/net/bagetlance.c b/drivers/net/bagetlance.c --- a/drivers/net/bagetlance.c Thu Jan 22 18:59:23 2004 +++ b/drivers/net/bagetlance.c Thu Jan 22 18:59:23 2004 @@ -465,30 +465,43 @@ } -int __init bagetlance_probe( struct net_device *dev ) - -{ int i; +struct net_device * __init bagetlance_probe(int unit) +{ + struct net_device *dev; + int i; static int found; - - SET_MODULE_OWNER(dev); + int err = -ENODEV; if (found) /* Assume there's only one board possible... That seems true, since * the Riebl/PAM board's address cannot be changed. */ - return( -ENODEV ); + return ERR_PTR(-ENODEV); + + dev = alloc_etherdev(sizeof(struct lance_private)); + if (!dev) + return ERR_PTR(-ENOMEM); + + SET_MODULE_OWNER(dev); for( i = 0; i < N_LANCE_ADDR; ++i ) { if (lance_probe1( dev, &lance_addr_list[i] )) { found = 1; - return( 0 ); + break; } } - - return( -ENODEV ); + if (!found) + goto out; + err = register_netdev(dev); + if (err) + goto out1; + return dev; +out1: + free_irq(dev->irq, dev); +out: + free_netdev(dev); + return ERR_PTR(err); } - - /* Derived from hwreg_present() in vme/config.c: */ static int __init addr_accessible( volatile void *regp, @@ -527,6 +540,7 @@ if (!addr_accessible( memaddr, 1, 1 )) goto probe_fail; if ((unsigned long)memaddr >= KSEG2) { + /* FIXME: do we need to undo that on cleanup paths? */ extern int kseg2_alloc_io (unsigned long addr, unsigned long size); if (kseg2_alloc_io((unsigned long)memaddr, BAGET_LANCE_MEM_SIZE)) { printk("bagetlance: unable map lance memory\n"); @@ -580,12 +594,6 @@ return( 0 ); probe_ok: - init_etherdev( dev, sizeof(struct lance_private) ); - if (!dev->priv) { - dev->priv = kmalloc( sizeof(struct lance_private), GFP_KERNEL ); - if (!dev->priv) - return 0; - } lp = (struct lance_private *)dev->priv; MEM = (struct lance_memory *)memaddr; IO = lp->iobase = (struct lance_ioreg *)ioaddr; @@ -617,8 +625,9 @@ if (lp->cardtype == PAM_CARD || memaddr == (unsigned short *)0xffe00000) { /* PAMs card and Riebl on ST use level 5 autovector */ - request_irq(BAGET_LANCE_IRQ, lance_interrupt, IRQ_TYPE_PRIO, - "PAM/Riebl-ST Ethernet", dev); + if (request_irq(BAGET_LANCE_IRQ, lance_interrupt, IRQ_TYPE_PRIO, + "PAM/Riebl-ST Ethernet", dev)) + goto probe_fail; dev->irq = (unsigned short)BAGET_LANCE_IRQ; } else { @@ -629,10 +638,11 @@ unsigned long irq = BAGET_LANCE_IRQ; if (!irq) { printk( "Lance: request for VME interrupt failed\n" ); - return( 0 ); + goto probe_fail; } - request_irq(irq, lance_interrupt, IRQ_TYPE_PRIO, - "Riebl-VME Ethernet", dev); + if (request_irq(irq, lance_interrupt, IRQ_TYPE_PRIO, + "Riebl-VME Ethernet", dev)) + goto probe_fail; dev->irq = irq; } @@ -1331,26 +1341,21 @@ #ifdef MODULE -static struct net_device bagetlance_dev; +static struct net_device *bagetlance_dev; int init_module(void) - -{ int err; - - bagetlance_dev.init = bagetlance_probe; - if ((err = register_netdev( &bagetlance_dev ))) { - if (err == -EIO) { - printk( "No Vme Lance board found. Module not loaded.\n"); - } - return( err ); - } - return( 0 ); +{ + bagetlance_dev = bagetlance_probe(-1); + if (IS_ERR(bagetlance_dev)) + return PTR_ERR(bagetlance_dev); + return 0; } void cleanup_module(void) - { - unregister_netdev( &bagetlance_dev ); + unregister_netdev(bagetlance_dev); + free_irq(bagetlance_dev->irq, bagetlance_dev); + free_netdev(bagetlance_dev); } #endif /* MODULE */ diff -Nru a/drivers/net/bonding/bond_3ad.c b/drivers/net/bonding/bond_3ad.c --- a/drivers/net/bonding/bond_3ad.c Thu Jan 22 18:59:26 2004 +++ b/drivers/net/bonding/bond_3ad.c Thu Jan 22 18:59:26 2004 @@ -1,5 +1,5 @@ /* - * Copyright(c) 1999 - 2003 Intel Corporation. All rights reserved. + * Copyright(c) 1999 - 2004 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free @@ -47,8 +47,13 @@ * - Send LACPDU as highest priority packet to further fix the above * problem on very high Tx traffic load where packets may get dropped * by the slave. + * + * 2003/12/01 - Shmulik Hen + * - Code cleanup and style changes */ +//#define BONDING_DEBUG 1 + #include #include #include @@ -119,6 +124,7 @@ static struct mac_addr null_mac_addr = {{0, 0, 0, 0, 0, 0}}; static u16 ad_ticks_per_sec; +static const int ad_delta_in_ticks = (AD_TIMER_INTERVAL * HZ) / 1000; // ================= 3AD api to bonding and kernel code ================== static u16 __get_link_speed(struct port *port); @@ -196,13 +202,11 @@ */ static inline struct port *__get_first_port(struct bonding *bond) { - struct slave *slave = bond->next; - - if (slave == (struct slave *)bond) { + if (bond->slave_cnt == 0) { return NULL; } - return &(SLAVE_AD_INFO(slave).port); + return &(SLAVE_AD_INFO(bond->first_slave).port); } /** @@ -218,7 +222,7 @@ struct slave *slave = port->slave; // If there's no bond for this port, or this is the last slave - if ((bond == NULL) || (slave->next == bond->next)) { + if ((bond == NULL) || (slave->next == bond->first_slave)) { return NULL; } @@ -236,12 +240,12 @@ { struct bonding *bond = __get_bond_by_port(port); - // If there's no bond for this port, or this is the last slave - if ((bond == NULL) || (bond->next == (struct slave *)bond)) { + // If there's no bond for this port, or bond has no slaves + if ((bond == NULL) || (bond->slave_cnt == 0)) { return NULL; } - return &(SLAVE_AD_INFO(bond->next).aggregator); + return &(SLAVE_AD_INFO(bond->first_slave).aggregator); } /** @@ -257,7 +261,7 @@ struct bonding *bond = bond_get_bond_by_slave(slave); // If there's no bond for this aggregator, or this is the last slave - if ((bond == NULL) || (slave->next == bond->next)) { + if ((bond == NULL) || (slave->next == bond->first_slave)) { return NULL; } @@ -392,7 +396,7 @@ } } - BOND_PRINT_DBG(("Port %d Received link speed %d update from adapter", port->actor_port_number, speed)); + dprintk("Port %d Received link speed %d update from adapter\n", port->actor_port_number, speed); return speed; } @@ -418,12 +422,12 @@ switch (slave->duplex) { case DUPLEX_FULL: retval=0x1; - BOND_PRINT_DBG(("Port %d Received status full duplex update from adapter", port->actor_port_number)); + dprintk("Port %d Received status full duplex update from adapter\n", port->actor_port_number); break; case DUPLEX_HALF: default: retval=0x0; - BOND_PRINT_DBG(("Port %d Received status NOT full duplex update from adapter", port->actor_port_number)); + dprintk("Port %d Received status NOT full duplex update from adapter\n", port->actor_port_number); break; } } @@ -1059,7 +1063,7 @@ // check if the state machine was changed if (port->sm_mux_state != last_state) { - BOND_PRINT_DBG(("Mux Machine: Port=%d, Last State=%d, Curr State=%d", port->actor_port_number, last_state, port->sm_mux_state)); + dprintk("Mux Machine: Port=%d, Last State=%d, Curr State=%d\n", port->actor_port_number, last_state, port->sm_mux_state); switch (port->sm_mux_state) { case AD_MUX_DETACHED: __detach_bond_from_agg(port); @@ -1158,7 +1162,7 @@ // check if the State machine was changed or new lacpdu arrived if ((port->sm_rx_state != last_state) || (lacpdu)) { - BOND_PRINT_DBG(("Rx Machine: Port=%d, Last State=%d, Curr State=%d", port->actor_port_number, last_state, port->sm_rx_state)); + dprintk("Rx Machine: Port=%d, Last State=%d, Curr State=%d\n", port->actor_port_number, last_state, port->sm_rx_state); switch (port->sm_rx_state) { case AD_RX_INITIALIZE: if (!(port->actor_oper_port_key & AD_DUPLEX_KEY_BITS)) { @@ -1204,7 +1208,7 @@ // detect loopback situation if (!MAC_ADDRESS_COMPARE(&(lacpdu->actor_system), &(port->actor_system))) { // INFO_RECEIVED_LOOPBACK_FRAMES - printk(KERN_ERR "bonding: An illegal loopback occurred on adapter (%s)\n", + printk(KERN_ERR DRV_NAME ": An illegal loopback occurred on adapter (%s)\n", port->slave->dev->name); printk(KERN_ERR "Check the configuration to verify that all Adapters " "are connected to 802.3ad compliant switch ports\n"); @@ -1245,7 +1249,7 @@ __update_lacpdu_from_port(port); // send the lacpdu if (ad_lacpdu_send(port) >= 0) { - BOND_PRINT_DBG(("Sent LACPDU on port %d", port->actor_port_number)); + dprintk("Sent LACPDU on port %d\n", port->actor_port_number); // mark ntt as false, so it will not be sent again until demanded port->ntt = 0; } @@ -1318,7 +1322,7 @@ // check if the state machine was changed if (port->sm_periodic_state != last_state) { - BOND_PRINT_DBG(("Periodic Machine: Port=%d, Last State=%d, Curr State=%d", port->actor_port_number, last_state, port->sm_periodic_state)); + dprintk("Periodic Machine: Port=%d, Last State=%d, Curr State=%d\n", port->actor_port_number, last_state, port->sm_periodic_state); switch (port->sm_periodic_state) { case AD_NO_PERIODIC: port->sm_periodic_timer_counter = 0; // zero timer @@ -1375,7 +1379,7 @@ port->next_port_in_aggregator=NULL; port->actor_port_aggregator_identifier=0; - BOND_PRINT_DBG(("Port %d left LAG %d", port->actor_port_number, temp_aggregator->aggregator_identifier)); + dprintk("Port %d left LAG %d\n", port->actor_port_number, temp_aggregator->aggregator_identifier); // if the aggregator is empty, clear its parameters, and set it ready to be attached if (!temp_aggregator->lag_ports) { ad_clear_agg(temp_aggregator); @@ -1384,7 +1388,7 @@ } } if (!curr_port) { // meaning: the port was related to an aggregator but was not on the aggregator port list - printk(KERN_WARNING "bonding: Warning: Port %d (on %s) was " + printk(KERN_WARNING DRV_NAME ": Warning: Port %d (on %s) was " "related to aggregator %d but was not on its port list\n", port->actor_port_number, port->slave->dev->name, port->aggregator->aggregator_identifier); @@ -1417,7 +1421,7 @@ port->next_port_in_aggregator=aggregator->lag_ports; port->aggregator->num_of_ports++; aggregator->lag_ports=port; - BOND_PRINT_DBG(("Port %d joined LAG %d(existing LAG)", port->actor_port_number, port->aggregator->aggregator_identifier)); + dprintk("Port %d joined LAG %d(existing LAG)\n", port->actor_port_number, port->aggregator->aggregator_identifier); // mark this port as selected port->sm_vars |= AD_PORT_SELECTED; @@ -1454,9 +1458,9 @@ // mark this port as selected port->sm_vars |= AD_PORT_SELECTED; - BOND_PRINT_DBG(("Port %d joined LAG %d(new LAG)", port->actor_port_number, port->aggregator->aggregator_identifier)); + dprintk("Port %d joined LAG %d(new LAG)\n", port->actor_port_number, port->aggregator->aggregator_identifier); } else { - printk(KERN_ERR "bonding: Port %d (on %s) did not find a suitable aggregator\n", + printk(KERN_ERR DRV_NAME ": Port %d (on %s) did not find a suitable aggregator\n", port->actor_port_number, port->slave->dev->name); } } @@ -1580,30 +1584,30 @@ aggregator; aggregator = __get_next_agg(aggregator)) { - BOND_PRINT_DBG(("Agg=%d; Ports=%d; a key=%d; p key=%d; Indiv=%d; Active=%d", + dprintk("Agg=%d; Ports=%d; a key=%d; p key=%d; Indiv=%d; Active=%d\n", aggregator->aggregator_identifier, aggregator->num_of_ports, aggregator->actor_oper_aggregator_key, aggregator->partner_oper_aggregator_key, - aggregator->is_individual, aggregator->is_active)); + aggregator->is_individual, aggregator->is_active); } // check if any partner replys if (best_aggregator->is_individual) { - printk(KERN_WARNING "bonding: Warning: No 802.3ad response from the link partner " + printk(KERN_WARNING DRV_NAME ": Warning: No 802.3ad response from the link partner " "for any adapters in the bond\n"); } // check if there are more than one aggregator if (num_of_aggs > 1) { - BOND_PRINT_DBG(("Warning: More than one Link Aggregation Group was " - "found in the bond. Only one group will function in the bond")); + dprintk("Warning: More than one Link Aggregation Group was " + "found in the bond. Only one group will function in the bond\n"); } best_aggregator->is_active = 1; - BOND_PRINT_DBG(("LAG %d choosed as the active LAG", best_aggregator->aggregator_identifier)); - BOND_PRINT_DBG(("Agg=%d; Ports=%d; a key=%d; p key=%d; Indiv=%d; Active=%d", + dprintk("LAG %d choosed as the active LAG\n", best_aggregator->aggregator_identifier); + dprintk("Agg=%d; Ports=%d; a key=%d; p key=%d; Indiv=%d; Active=%d\n", best_aggregator->aggregator_identifier, best_aggregator->num_of_ports, best_aggregator->actor_oper_aggregator_key, best_aggregator->partner_oper_aggregator_key, - best_aggregator->is_individual, best_aggregator->is_active)); + best_aggregator->is_individual, best_aggregator->is_active); // disable the ports that were related to the former active_aggregator if (last_active_aggregator) { @@ -1644,7 +1648,7 @@ aggregator->lag_ports = NULL; aggregator->is_active = 0; aggregator->num_of_ports = 0; - BOND_PRINT_DBG(("LAG %d was cleared", aggregator->aggregator_identifier)); + dprintk("LAG %d was cleared\n", aggregator->aggregator_identifier); } } @@ -1729,7 +1733,7 @@ static void ad_enable_collecting_distributing(struct port *port) { if (port->aggregator->is_active) { - BOND_PRINT_DBG(("Enabling port %d(LAG %d)", port->actor_port_number, port->aggregator->aggregator_identifier)); + dprintk("Enabling port %d(LAG %d)\n", port->actor_port_number, port->aggregator->aggregator_identifier); __enable_port(port); } } @@ -1742,7 +1746,7 @@ static void ad_disable_collecting_distributing(struct port *port) { if (port->aggregator && MAC_ADDRESS_COMPARE(&(port->aggregator->partner_system), &(null_mac_addr))) { - BOND_PRINT_DBG(("Disabling port %d(LAG %d)", port->actor_port_number, port->aggregator->aggregator_identifier)); + dprintk("Disabling port %d(LAG %d)\n", port->actor_port_number, port->aggregator->aggregator_identifier); __disable_port(port); } } @@ -1780,7 +1784,7 @@ // send the marker information if (ad_marker_send(port, &marker) >= 0) { - BOND_PRINT_DBG(("Sent Marker Information on port %d", port->actor_port_number)); + dprintk("Sent Marker Information on port %d\n", port->actor_port_number); } } #endif @@ -1803,7 +1807,7 @@ // send the marker response if (ad_marker_send(port, &marker) >= 0) { - BOND_PRINT_DBG(("Sent Marker Response on port %d", port->actor_port_number)); + dprintk("Sent Marker Response on port %d\n", port->actor_port_number); } } @@ -1890,13 +1894,13 @@ void bond_3ad_initialize(struct bonding *bond, u16 tick_resolution, int lacp_fast) { // check that the bond is not initialized yet - if (MAC_ADDRESS_COMPARE(&(BOND_AD_INFO(bond).system.sys_mac_addr), &(bond->device->dev_addr))) { + if (MAC_ADDRESS_COMPARE(&(BOND_AD_INFO(bond).system.sys_mac_addr), &(bond->dev->dev_addr))) { aggregator_identifier = 0; BOND_AD_INFO(bond).lacp_fast = lacp_fast; BOND_AD_INFO(bond).system.sys_priority = 0xFFFF; - BOND_AD_INFO(bond).system.sys_mac_addr = *((struct mac_addr *)bond->device->dev_addr); + BOND_AD_INFO(bond).system.sys_mac_addr = *((struct mac_addr *)bond->dev->dev_addr); // initialize how many times this module is called in one second(should be about every 100ms) ad_ticks_per_sec = tick_resolution; @@ -1921,7 +1925,7 @@ struct aggregator *aggregator; if (bond == NULL) { - printk(KERN_CRIT "The slave %s is not attached to its bond\n", slave->dev->name); + printk(KERN_ERR "The slave %s is not attached to its bond\n", slave->dev->name); return -1; } @@ -1964,7 +1968,7 @@ ad_initialize_agg(aggregator); - aggregator->aggregator_mac_address = *((struct mac_addr *)bond->device->dev_addr); + aggregator->aggregator_mac_address = *((struct mac_addr *)bond->dev->dev_addr); aggregator->aggregator_identifier = (++aggregator_identifier); aggregator->slave = slave; aggregator->is_active = 0; @@ -1996,11 +2000,11 @@ // if slave is null, the whole port is not initialized if (!port->slave) { - printk(KERN_WARNING "bonding: Trying to unbind an uninitialized port on %s\n", slave->dev->name); + printk(KERN_WARNING DRV_NAME ": Trying to unbind an uninitialized port on %s\n", slave->dev->name); return; } - BOND_PRINT_DBG(("Unbinding Link Aggregation Group %d", aggregator->aggregator_identifier)); + dprintk("Unbinding Link Aggregation Group %d\n", aggregator->aggregator_identifier); /* Tell the partner that this port is not suitable for aggregation */ port->actor_oper_port_state &= ~AD_STATE_AGGREGATION; @@ -2024,10 +2028,10 @@ // if new aggregator found, copy the aggregator's parameters // and connect the related lag_ports to the new aggregator if ((new_aggregator) && ((!new_aggregator->lag_ports) || ((new_aggregator->lag_ports == port) && !new_aggregator->lag_ports->next_port_in_aggregator))) { - BOND_PRINT_DBG(("Some port(s) related to LAG %d - replaceing with LAG %d", aggregator->aggregator_identifier, new_aggregator->aggregator_identifier)); + dprintk("Some port(s) related to LAG %d - replaceing with LAG %d\n", aggregator->aggregator_identifier, new_aggregator->aggregator_identifier); if ((new_aggregator->lag_ports == port) && new_aggregator->is_active) { - printk(KERN_INFO "bonding: Removing an active aggregator\n"); + printk(KERN_INFO DRV_NAME ": Removing an active aggregator\n"); // select new active aggregator select_new_active_agg = 1; } @@ -2057,7 +2061,7 @@ ad_agg_selection_logic(__get_first_agg(port)); } } else { - printk(KERN_WARNING "bonding: Warning: unbinding aggregator, " + printk(KERN_WARNING DRV_NAME ": Warning: unbinding aggregator, " "and could not find a new aggregator for its ports\n"); } } else { // in case that the only port related to this aggregator is the one we want to remove @@ -2072,7 +2076,7 @@ } } - BOND_PRINT_DBG(("Unbinding port %d", port->actor_port_number)); + dprintk("Unbinding port %d\n", port->actor_port_number); // find the aggregator that this port is connected to temp_aggregator = __get_first_agg(port); for (; temp_aggregator; temp_aggregator = __get_next_agg(temp_aggregator)) { @@ -2123,13 +2127,13 @@ read_lock(&bond->lock); - //check if there are any slaves - if (bond->next == (struct slave *)bond) { - goto end; + if (bond->kill_timers) { + goto out; } - if ((bond->device->flags & IFF_UP) != IFF_UP) { - goto end; + //check if there are any slaves + if (bond->slave_cnt == 0) { + goto re_arm; } // check if agg_select_timer timer after initialize is timed out @@ -2137,8 +2141,8 @@ // select the active aggregator for the bond if ((port = __get_first_port(bond))) { if (!port->slave) { - printk(KERN_WARNING "bonding: Warning: bond's first port is uninitialized\n"); - goto end; + printk(KERN_WARNING DRV_NAME ": Warning: bond's first port is uninitialized\n"); + goto re_arm; } aggregator = __get_first_agg(port); @@ -2149,8 +2153,8 @@ // for each port run the state machines for (port = __get_first_port(bond); port; port = __get_next_port(port)) { if (!port->slave) { - printk(KERN_WARNING "bonding: Warning: Found an uninitialized port\n"); - goto end; + printk(KERN_WARNING DRV_NAME ": Warning: Found an uninitialized port\n"); + goto re_arm; } ad_rx_machine(NULL, port); @@ -2165,14 +2169,10 @@ } } -end: +re_arm: + mod_timer(&(BOND_AD_INFO(bond).ad_timer), jiffies + ad_delta_in_ticks); +out: read_unlock(&bond->lock); - - - if ((bond->device->flags & IFF_UP) == IFF_UP) { - /* re-arm the timer */ - mod_timer(&(BOND_AD_INFO(bond).ad_timer), jiffies + (AD_TIMER_INTERVAL * HZ / 1000)); - } } /** @@ -2194,14 +2194,14 @@ port = &(SLAVE_AD_INFO(slave).port); if (!port->slave) { - printk(KERN_WARNING "bonding: Warning: port of slave %s is uninitialized\n", slave->dev->name); + printk(KERN_WARNING DRV_NAME ": Warning: port of slave %s is uninitialized\n", slave->dev->name); return; } switch (lacpdu->subtype) { case AD_TYPE_LACPDU: __ntohs_lacpdu(lacpdu); - BOND_PRINT_DBG(("Received LACPDU on port %d", port->actor_port_number)); + dprintk("Received LACPDU on port %d\n", port->actor_port_number); ad_rx_machine(lacpdu, port); break; @@ -2210,17 +2210,17 @@ switch (((struct marker *)lacpdu)->tlv_type) { case AD_MARKER_INFORMATION_SUBTYPE: - BOND_PRINT_DBG(("Received Marker Information on port %d", port->actor_port_number)); + dprintk("Received Marker Information on port %d\n", port->actor_port_number); ad_marker_info_received((struct marker *)lacpdu, port); break; case AD_MARKER_RESPONSE_SUBTYPE: - BOND_PRINT_DBG(("Received Marker Response on port %d", port->actor_port_number)); + dprintk("Received Marker Response on port %d\n", port->actor_port_number); ad_marker_response_received((struct marker *)lacpdu, port); break; default: - BOND_PRINT_DBG(("Received an unknown Marker subtype on slot %d", port->actor_port_number)); + dprintk("Received an unknown Marker subtype on slot %d\n", port->actor_port_number); } } } @@ -2240,14 +2240,14 @@ // if slave is null, the whole port is not initialized if (!port->slave) { - printk(KERN_WARNING "bonding: Warning: speed changed for uninitialized port on %s\n", + printk(KERN_WARNING DRV_NAME ": Warning: speed changed for uninitialized port on %s\n", slave->dev->name); return; } port->actor_admin_port_key &= ~AD_SPEED_KEY_BITS; port->actor_oper_port_key=port->actor_admin_port_key |= (__get_link_speed(port) << 1); - BOND_PRINT_DBG(("Port %d changed speed", port->actor_port_number)); + dprintk("Port %d changed speed\n", port->actor_port_number); // there is no need to reselect a new aggregator, just signal the // state machines to reinitialize port->sm_vars |= AD_PORT_BEGIN; @@ -2267,14 +2267,14 @@ // if slave is null, the whole port is not initialized if (!port->slave) { - printk(KERN_WARNING "bonding: Warning: duplex changed for uninitialized port on %s\n", + printk(KERN_WARNING DRV_NAME ": Warning: duplex changed for uninitialized port on %s\n", slave->dev->name); return; } port->actor_admin_port_key &= ~AD_DUPLEX_KEY_BITS; port->actor_oper_port_key=port->actor_admin_port_key |= __get_duplex(port); - BOND_PRINT_DBG(("Port %d changed duplex", port->actor_port_number)); + dprintk("Port %d changed duplex\n", port->actor_port_number); // there is no need to reselect a new aggregator, just signal the // state machines to reinitialize port->sm_vars |= AD_PORT_BEGIN; @@ -2295,10 +2295,8 @@ // if slave is null, the whole port is not initialized if (!port->slave) { -#ifdef BONDING_DEBUG - printk(KERN_WARNING "bonding: Warning: link status changed for uninitialized port on %s\n", - slave->dev->name); -#endif + printk(KERN_WARNING DRV_NAME ": Warning: link status changed for uninitialized port on %s\n", + slave->dev->name); return; } @@ -2356,41 +2354,27 @@ int bond_3ad_xmit_xor(struct sk_buff *skb, struct net_device *dev) { - slave_t *slave, *start_at; - struct bonding *bond = (struct bonding *) dev->priv; + struct slave *slave, *start_at; + struct bonding *bond = dev->priv; struct ethhdr *data = (struct ethhdr *)skb->data; int slave_agg_no; int slaves_in_agg; int agg_id; + int i; struct ad_info ad_info; - if (!IS_UP(dev)) { /* bond down */ - dev_kfree_skb(skb); - return 0; - } - - if (bond == NULL) { - printk(KERN_CRIT "bonding: Error: bond is NULL on device %s\n", dev->name); - dev_kfree_skb(skb); - return 0; - } - + /* make sure that the slaves list will + * not change during tx + */ read_lock(&bond->lock); - slave = bond->prev; - /* check if bond is empty */ - if ((slave == (struct slave *) bond) || (bond->slave_cnt == 0)) { - printk(KERN_DEBUG "ERROR: bond is empty\n"); - dev_kfree_skb(skb); - read_unlock(&bond->lock); - return 0; + if (!BOND_IS_OK(bond)) { + goto free_out; } if (bond_3ad_get_active_agg_info(bond, &ad_info)) { printk(KERN_DEBUG "ERROR: bond_3ad_get_active_agg_info failed\n"); - dev_kfree_skb(skb); - read_unlock(&bond->lock); - return 0; + goto free_out; } slaves_in_agg = ad_info.ports; @@ -2399,21 +2383,12 @@ if (slaves_in_agg == 0) { /*the aggregator is empty*/ printk(KERN_DEBUG "ERROR: active aggregator is empty\n"); - dev_kfree_skb(skb); - read_unlock(&bond->lock); - return 0; + goto free_out; } - /* we're at the root, get the first slave */ - if ((slave == NULL) || (slave->dev == NULL)) { - /* no suitable interface, frame not sent */ - dev_kfree_skb(skb); - read_unlock(&bond->lock); - return 0; - } + slave_agg_no = (data->h_dest[5]^bond->dev->dev_addr[5]) % slaves_in_agg; - slave_agg_no = (data->h_dest[5]^slave->dev->dev_addr[5]) % slaves_in_agg; - while (slave != (slave_t *)bond) { + bond_for_each_slave(bond, slave, i) { struct aggregator *agg = SLAVE_AD_INFO(slave).port.aggregator; if (agg && (agg->aggregator_identifier == agg_id)) { @@ -2422,37 +2397,18 @@ break; } } - - slave = slave->prev; - if (slave == NULL) { - printk(KERN_ERR "bonding: Error: slave is NULL\n"); - dev_kfree_skb(skb); - read_unlock(&bond->lock); - return 0; - } } - if (slave == (slave_t *)bond) { - printk(KERN_ERR "bonding: Error: Couldn't find a slave to tx on for aggregator ID %d\n", agg_id); - dev_kfree_skb(skb); - read_unlock(&bond->lock); - return 0; + if (slave_agg_no >= 0) { + printk(KERN_ERR DRV_NAME ": Error: Couldn't find a slave to tx on for aggregator ID %d\n", agg_id); + goto free_out; } start_at = slave; - do { + bond_for_each_slave_from(bond, slave, i, start_at) { int slave_agg_id = 0; - struct aggregator *agg; - - if (slave == NULL) { - printk(KERN_ERR "bonding: Error: slave is NULL\n"); - dev_kfree_skb(skb); - read_unlock(&bond->lock); - return 0; - } - - agg = SLAVE_AD_INFO(slave).port.aggregator; + struct aggregator *agg = SLAVE_AD_INFO(slave).port.aggregator; if (agg) { slave_agg_id = agg->aggregator_identifier; @@ -2463,20 +2419,24 @@ skb->dev = slave->dev; skb->priority = 1; dev_queue_xmit(skb); - read_unlock(&bond->lock); - return 0; + + goto out; } - } while ((slave = slave->next) != start_at); + } - /* no suitable interface, frame not sent */ - dev_kfree_skb(skb); +out: read_unlock(&bond->lock); return 0; + +free_out: + /* no suitable interface, frame not sent */ + dev_kfree_skb(skb); + goto out; } int bond_3ad_lacpdu_recv(struct sk_buff *skb, struct net_device *dev, struct packet_type* ptype) { - struct bonding *bond = (struct bonding *)dev->priv; + struct bonding *bond = dev->priv; struct slave *slave = NULL; int ret = NET_RX_DROP; diff -Nru a/drivers/net/bonding/bond_3ad.h b/drivers/net/bonding/bond_3ad.h --- a/drivers/net/bonding/bond_3ad.h Thu Jan 22 18:59:27 2004 +++ b/drivers/net/bonding/bond_3ad.h Thu Jan 22 18:59:27 2004 @@ -1,5 +1,5 @@ /* - * Copyright(c) 1999 - 2003 Intel Corporation. All rights reserved. + * Copyright(c) 1999 - 2004 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free @@ -28,6 +28,9 @@ * 2003/05/01 - Shmulik Hen * - Renamed bond_3ad_link_status_changed() to * bond_3ad_handle_link_change() for compatibility with TLB. + * + * 2003/12/01 - Shmulik Hen + * - Code cleanup and style changes */ #ifndef __BOND_3AD_H__ diff -Nru a/drivers/net/bonding/bond_alb.c b/drivers/net/bonding/bond_alb.c --- a/drivers/net/bonding/bond_alb.c Thu Jan 22 18:59:26 2004 +++ b/drivers/net/bonding/bond_alb.c Thu Jan 22 18:59:26 2004 @@ -1,5 +1,5 @@ /* - * Copyright(c) 1999 - 2003 Intel Corporation. All rights reserved. + * Copyright(c) 1999 - 2004 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -28,8 +28,16 @@ * 2003/08/06 - Amir Noam * - Add support for setting bond's MAC address with special * handling required for ALB/TLB. + * + * 2003/12/01 - Shmulik Hen + * - Code cleanup and style changes + * + * 2003/12/30 - Amir Noam + * - Fixed: Cannot remove and re-enslave the original active slave. */ +//#define BONDING_DEBUG 1 + #include #include #include @@ -50,11 +58,11 @@ #define ALB_TIMER_TICKS_PER_SEC 10 /* should be a divisor of HZ */ -#define BOND_TLB_REBALANCE_INTERVAL 10 /* in seconds, periodic re-balancing - * used for division - never set +#define BOND_TLB_REBALANCE_INTERVAL 10 /* In seconds, periodic re-balancing. + * Used for division - never set * to zero !!! */ -#define BOND_ALB_LP_INTERVAL 1 /* in seconds periodic send of +#define BOND_ALB_LP_INTERVAL 1 /* In seconds, periodic send of * learning packets to the switch */ @@ -66,7 +74,7 @@ #define TLB_HASH_TABLE_SIZE 256 /* The size of the clients hash table. * Note that this value MUST NOT be smaller - * because the key hash table BYTE wide ! + * because the key hash table is BYTE wide ! */ @@ -86,12 +94,15 @@ */ #define RLB_PROMISC_TIMEOUT 10*ALB_TIMER_TICKS_PER_SEC +static const u8 mac_bcast[ETH_ALEN] = {0xff,0xff,0xff,0xff,0xff,0xff}; +static const int alb_delta_in_ticks = HZ / ALB_TIMER_TICKS_PER_SEC; + #pragma pack(1) struct learning_pkt { u8 mac_dst[ETH_ALEN]; u8 mac_src[ETH_ALEN]; u16 type; - u8 padding[ETH_ZLEN - (2*ETH_ALEN + 2)]; + u8 padding[ETH_ZLEN - ETH_HLEN]; }; struct arp_pkt { @@ -110,13 +121,12 @@ /* Forward declaration */ static void alb_send_learning_packets(struct slave *slave, u8 mac_addr[]); -static inline u8 -_simple_hash(u8 *hash_start, int hash_size) +static inline u8 _simple_hash(u8 *hash_start, int hash_size) { int i; u8 hash = 0; - for (i=0; iload_history = 1 + entry->tx_bytes / - BOND_TLB_REBALANCE_INTERVAL; + BOND_TLB_REBALANCE_INTERVAL; entry->tx_bytes = 0; } + entry->tx_slave = NULL; entry->next = TLB_NULL_INDEX; entry->prev = TLB_NULL_INDEX; } -static inline void -tlb_init_slave(struct slave *slave) +static inline void tlb_init_slave(struct slave *slave) { - struct tlb_slave_info *slave_info = &(SLAVE_TLB_INFO(slave)); - - slave_info->load = 0; - slave_info->head = TLB_NULL_INDEX; + SLAVE_TLB_INFO(slave).load = 0; + SLAVE_TLB_INFO(slave).head = TLB_NULL_INDEX; } /* Caller must hold bond lock for read */ -static inline void -tlb_clear_slave(struct bonding *bond, struct slave *slave, u8 save_load) +static void tlb_clear_slave(struct bonding *bond, struct slave *slave, int save_load) { - struct tlb_client_info *tx_hash_table = NULL; - u32 index, next_index; + struct tlb_client_info *tx_hash_table; + u32 index; - /* clear slave from tx_hashtbl */ _lock_tx_hashtbl(bond); + + /* clear slave from tx_hashtbl */ tx_hash_table = BOND_ALB_INFO(bond).tx_hashtbl; - if (tx_hash_table) { - index = SLAVE_TLB_INFO(slave).head; - while (index != TLB_NULL_INDEX) { - next_index = tx_hash_table[index].next; - tlb_init_table_entry(bond, index, save_load); - index = next_index; - } + index = SLAVE_TLB_INFO(slave).head; + while (index != TLB_NULL_INDEX) { + u32 next_index = tx_hash_table[index].next; + tlb_init_table_entry(&tx_hash_table[index], save_load); + index = next_index; } + _unlock_tx_hashtbl(bond); tlb_init_slave(slave); } /* Must be called before starting the monitor timer */ -static int -tlb_initialize(struct bonding *bond) +static int tlb_initialize(struct bonding *bond) { struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond)); + int size = TLB_HASH_TABLE_SIZE * sizeof(struct tlb_client_info); int i; - size_t size; - -#if(TLB_HASH_TABLE_SIZE != 256) - /* Key to the hash table is byte wide. Check the size! */ - #error Hash Table size is wrong. -#endif spin_lock_init(&(bond_info->tx_hashtbl_lock)); _lock_tx_hashtbl(bond); - if (bond_info->tx_hashtbl != NULL) { - printk (KERN_ERR "%s: TLB hash table is not NULL\n", - bond->device->name); - _unlock_tx_hashtbl(bond); - return -1; - } - size = TLB_HASH_TABLE_SIZE * sizeof(struct tlb_client_info); bond_info->tx_hashtbl = kmalloc(size, GFP_KERNEL); - if (bond_info->tx_hashtbl == NULL) { - printk (KERN_ERR "%s: Failed to allocate TLB hash table\n", - bond->device->name); + if (!bond_info->tx_hashtbl) { + printk(KERN_ERR DRV_NAME + ": Error: %s: Failed to allocate TLB hash table\n", + bond->dev->name); _unlock_tx_hashtbl(bond); return -1; } memset(bond_info->tx_hashtbl, 0, size); - for (i=0; itx_hashtbl[i], 1); } + _unlock_tx_hashtbl(bond); return 0; } /* Must be called only after all slaves have been released */ -static void -tlb_deinitialize(struct bonding *bond) +static void tlb_deinitialize(struct bonding *bond) { struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond)); _lock_tx_hashtbl(bond); - if (bond_info->tx_hashtbl == NULL) { - _unlock_tx_hashtbl(bond); - return; - } + kfree(bond_info->tx_hashtbl); bond_info->tx_hashtbl = NULL; + _unlock_tx_hashtbl(bond); } /* Caller must hold bond lock for read */ -static struct slave* -tlb_get_least_loaded_slave(struct bonding *bond) +static struct slave *tlb_get_least_loaded_slave(struct bonding *bond) { - struct slave *slave; - struct slave *least_loaded; - s64 curr_gap, max_gap; + struct slave *slave, *least_loaded; + s64 max_gap; + int i, found = 0; /* Find the first enabled slave */ - slave = bond_get_first_slave(bond); - while (slave) { + bond_for_each_slave(bond, slave, i) { if (SLAVE_IS_OK(slave)) { + found = 1; break; } - slave = bond_get_next_slave(bond, slave); } - if (!slave) { + if (!found) { return NULL; } least_loaded = slave; - max_gap = (s64)(slave->speed * 1000000) - - (s64)(SLAVE_TLB_INFO(slave).load * 8); + max_gap = (s64)(slave->speed << 20) - /* Convert to Megabit per sec */ + (s64)(SLAVE_TLB_INFO(slave).load << 3); /* Bytes to bits */ /* Find the slave with the largest gap */ - slave = bond_get_next_slave(bond, slave); - while (slave) { + bond_for_each_slave_from(bond, slave, i, least_loaded) { if (SLAVE_IS_OK(slave)) { - curr_gap = (s64)(slave->speed * 1000000) - - (s64)(SLAVE_TLB_INFO(slave).load * 8); - if (max_gap < curr_gap) { + s64 gap = (s64)(slave->speed << 20) - + (s64)(SLAVE_TLB_INFO(slave).load << 3); + if (max_gap < gap) { least_loaded = slave; - max_gap = curr_gap; + max_gap = gap; } } - slave = bond_get_next_slave(bond, slave); } return least_loaded; } /* Caller must hold bond lock for read */ -struct slave* -tlb_choose_channel(struct bonding *bond, u32 hash_index, u32 skb_len) +struct slave *tlb_choose_channel(struct bonding *bond, u32 hash_index, u32 skb_len) { struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond)); - struct tlb_client_info *hash_table = NULL; - struct slave *assigned_slave = NULL; + struct tlb_client_info *hash_table; + struct slave *assigned_slave; _lock_tx_hashtbl(bond); hash_table = bond_info->tx_hashtbl; - if (hash_table == NULL) { - printk (KERN_ERR "%s: TLB hash table is NULL\n", - bond->device->name); - _unlock_tx_hashtbl(bond); - return NULL; - } - assigned_slave = hash_table[hash_index].tx_slave; if (!assigned_slave) { assigned_slave = tlb_get_least_loaded_slave(bond); @@ -345,14 +313,12 @@ } /*********************** rlb specific functions ***************************/ -static inline void -_lock_rx_hashtbl(struct bonding *bond) +static inline void _lock_rx_hashtbl(struct bonding *bond) { spin_lock(&(BOND_ALB_INFO(bond).rx_hashtbl_lock)); } -static inline void -_unlock_rx_hashtbl(struct bonding *bond) +static inline void _unlock_rx_hashtbl(struct bonding *bond) { spin_unlock(&(BOND_ALB_INFO(bond).rx_hashtbl_lock)); } @@ -360,26 +326,20 @@ /* when an ARP REPLY is received from a client update its info * in the rx_hashtbl */ -static void -rlb_update_entry_from_arp(struct bonding *bond, struct arp_pkt *arp) +static void rlb_update_entry_from_arp(struct bonding *bond, struct arp_pkt *arp) { - u32 hash_index; - struct rlb_client_info *client_info = NULL; struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond)); + struct rlb_client_info *client_info; + u32 hash_index; _lock_rx_hashtbl(bond); - if (bond_info->rx_hashtbl == NULL) { - _unlock_rx_hashtbl(bond); - return; - } - hash_index = _simple_hash((u8*)&(arp->ip_src), 4); + hash_index = _simple_hash((u8*)&(arp->ip_src), sizeof(arp->ip_src)); client_info = &(bond_info->rx_hashtbl[hash_index]); if ((client_info->assigned) && (client_info->ip_src == arp->ip_dst) && (client_info->ip_dst == arp->ip_src)) { - /* update the clients MAC address */ memcpy(client_info->mac_dst, arp->mac_src, ETH_ALEN); client_info->ntt = 1; @@ -389,66 +349,60 @@ _unlock_rx_hashtbl(bond); } -static int -rlb_arp_recv(struct sk_buff *skb, - struct net_device *dev, - struct packet_type* ptype) +static int rlb_arp_recv(struct sk_buff *skb, struct net_device *bond_dev, struct packet_type *ptype) { - struct bonding *bond = (struct bonding *)dev->priv; - int ret = NET_RX_DROP; + struct bonding *bond = bond_dev->priv; struct arp_pkt *arp = (struct arp_pkt *)skb->data; + int res = NET_RX_DROP; - if (!(dev->flags & IFF_MASTER)) { + if (!(bond_dev->flags & IFF_MASTER)) { goto out; } if (!arp) { - printk(KERN_ERR "Packet has no ARP data\n"); + dprintk("Packet has no ARP data\n"); goto out; } if (skb->len < sizeof(struct arp_pkt)) { - printk(KERN_ERR "Packet is too small to be an ARP\n"); + dprintk("Packet is too small to be an ARP\n"); goto out; } if (arp->op_code == htons(ARPOP_REPLY)) { /* update rx hash table for this ARP */ rlb_update_entry_from_arp(bond, arp); - BOND_PRINT_DBG(("Server received an ARP Reply from client")); + dprintk("Server received an ARP Reply from client\n"); } - ret = NET_RX_SUCCESS; + res = NET_RX_SUCCESS; out: dev_kfree_skb(skb); - return ret; + return res; } /* Caller must hold bond lock for read */ -static struct slave* -rlb_next_rx_slave(struct bonding *bond) +static struct slave *rlb_next_rx_slave(struct bonding *bond) { - struct slave *rx_slave = NULL, *slave = NULL; - unsigned int i = 0; struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond)); + struct slave *rx_slave, *slave, *start_at; + int i = 0; - slave = bond_info->next_rx_slave; - if (slave == NULL) { - slave = bond->next; + if (bond_info->next_rx_slave) { + start_at = bond_info->next_rx_slave; + } else { + start_at = bond->first_slave; } - /* this loop uses the circular linked list property of the - * slave's list to go through all slaves - */ - for (i = 0; i < bond->slave_cnt; i++, slave = slave->next) { + rx_slave = NULL; + bond_for_each_slave_from(bond, slave, i, start_at) { if (SLAVE_IS_OK(slave)) { if (!rx_slave) { rx_slave = slave; - } - else if (slave->speed > rx_slave->speed) { + } else if (slave->speed > rx_slave->speed) { rx_slave = slave; } } @@ -464,48 +418,41 @@ /* teach the switch the mac of a disabled slave * on the primary for fault tolerance * - * Caller must hold bond->ptrlock for write or bond lock for write + * Caller must hold bond->curr_slave_lock for write or bond lock for write */ -static void -rlb_teach_disabled_mac_on_primary(struct bonding *bond, u8 addr[]) +static void rlb_teach_disabled_mac_on_primary(struct bonding *bond, u8 addr[]) { - if (!bond->current_slave) { + if (!bond->curr_active_slave) { return; } + if (!bond->alb_info.primary_is_promisc) { bond->alb_info.primary_is_promisc = 1; - dev_set_promiscuity(bond->current_slave->dev, 1); + dev_set_promiscuity(bond->curr_active_slave->dev, 1); } + bond->alb_info.rlb_promisc_timeout_counter = 0; - alb_send_learning_packets(bond->current_slave, addr); + alb_send_learning_packets(bond->curr_active_slave, addr); } /* slave being removed should not be active at this point * * Caller must hold bond lock for read */ -static void -rlb_clear_slave(struct bonding *bond, struct slave *slave) +static void rlb_clear_slave(struct bonding *bond, struct slave *slave) { - struct rlb_client_info *rx_hash_table = NULL; struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond)); - u8 mac_bcast[ETH_ALEN] = {0xff,0xff,0xff,0xff,0xff,0xff}; + struct rlb_client_info *rx_hash_table; u32 index, next_index; /* clear slave from rx_hashtbl */ _lock_rx_hashtbl(bond); - rx_hash_table = bond_info->rx_hashtbl; - - if (rx_hash_table == NULL) { - _unlock_rx_hashtbl(bond); - return; - } + rx_hash_table = bond_info->rx_hashtbl; index = bond_info->rx_hashtbl_head; for (; index != RLB_NULL_INDEX; index = next_index) { next_index = rx_hash_table[index].next; - if (rx_hash_table[index].slave == slave) { struct slave *assigned_slave = rlb_next_rx_slave(bond); @@ -533,23 +480,24 @@ _unlock_rx_hashtbl(bond); - write_lock(&bond->ptrlock); - if (slave != bond->current_slave) { + write_lock(&bond->curr_slave_lock); + + if (slave != bond->curr_active_slave) { rlb_teach_disabled_mac_on_primary(bond, slave->dev->dev_addr); } - write_unlock(&bond->ptrlock); + + write_unlock(&bond->curr_slave_lock); } -static void -rlb_update_client(struct rlb_client_info *client_info) +static void rlb_update_client(struct rlb_client_info *client_info) { - int i = 0; + int i; - if (client_info->slave == NULL) { + if (!client_info->slave) { return; } - for (i=0; iip_dst, client_info->slave->dev, @@ -561,20 +509,14 @@ } /* sends ARP REPLIES that update the clients that need updating */ -static void -rlb_update_rx_clients(struct bonding *bond) +static void rlb_update_rx_clients(struct bonding *bond) { - u32 hash_index; - struct rlb_client_info *client_info = NULL; struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond)); + struct rlb_client_info *client_info; + u32 hash_index; _lock_rx_hashtbl(bond); - if (bond_info->rx_hashtbl == NULL) { - _unlock_rx_hashtbl(bond); - return; - } - hash_index = bond_info->rx_hashtbl_head; for (; hash_index != RLB_NULL_INDEX; hash_index = client_info->next) { client_info = &(bond_info->rx_hashtbl[hash_index]); @@ -595,22 +537,15 @@ } /* The slave was assigned a new mac address - update the clients */ -static void -rlb_req_update_slave_clients(struct bonding *bond, struct slave *slave) +static void rlb_req_update_slave_clients(struct bonding *bond, struct slave *slave) { - u32 hash_index; - u8 ntt = 0; struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond)); - u8 mac_bcast[ETH_ALEN] = {0xff,0xff,0xff,0xff,0xff,0xff}; - struct rlb_client_info* client_info = NULL; + struct rlb_client_info *client_info; + int ntt = 0; + u32 hash_index; _lock_rx_hashtbl(bond); - if (bond_info->rx_hashtbl == NULL) { - _unlock_rx_hashtbl(bond); - return; - } - hash_index = bond_info->rx_hashtbl_head; for (; hash_index != RLB_NULL_INDEX; hash_index = client_info->next) { client_info = &(bond_info->rx_hashtbl[hash_index]); @@ -633,37 +568,31 @@ } /* mark all clients using src_ip to be updated */ -static void -rlb_req_update_subnet_clients(struct bonding *bond, u32 src_ip) +static void rlb_req_update_subnet_clients(struct bonding *bond, u32 src_ip) { - u32 hash_index; struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond)); - u8 mac_bcast[ETH_ALEN] = {0xff,0xff,0xff,0xff,0xff,0xff}; - struct rlb_client_info *client_info = NULL; + struct rlb_client_info *client_info; + u32 hash_index; _lock_rx_hashtbl(bond); - if (bond_info->rx_hashtbl == NULL) { - _unlock_rx_hashtbl(bond); - return; - } - hash_index = bond_info->rx_hashtbl_head; for (; hash_index != RLB_NULL_INDEX; hash_index = client_info->next) { client_info = &(bond_info->rx_hashtbl[hash_index]); if (!client_info->slave) { - printk(KERN_ERR "Bonding: Error: found a client with no" - " channel in the client's hash table\n"); + printk(KERN_ERR DRV_NAME + ": Error: found a client with no channel in " + "the client's hash table\n"); continue; } /*update all clients using this src_ip, that are not assigned - * to the team's address (current_slave) and have a known + * to the team's address (curr_active_slave) and have a known * unicast mac address. */ if ((client_info->ip_src == src_ip) && memcmp(client_info->slave->dev->dev_addr, - bond->device->dev_addr, ETH_ALEN) && + bond->dev->dev_addr, ETH_ALEN) && memcmp(client_info->mac_dst, mac_bcast, ETH_ALEN)) { client_info->ntt = 1; bond_info->rx_ntt = 1; @@ -674,30 +603,22 @@ } /* Caller must hold both bond and ptr locks for read */ -struct slave* -rlb_choose_channel(struct bonding *bond, struct arp_pkt *arp) +struct slave *rlb_choose_channel(struct bonding *bond, struct arp_pkt *arp) { struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond)); - struct rlb_client_info *client_info = NULL; + struct slave *assigned_slave; + struct rlb_client_info *client_info; u32 hash_index = 0; - struct slave *assigned_slave = NULL; - u8 mac_bcast[ETH_ALEN] = {0xff,0xff,0xff,0xff,0xff,0xff}; _lock_rx_hashtbl(bond); - if (bond_info->rx_hashtbl == NULL) { - _unlock_rx_hashtbl(bond); - return NULL; - } - - hash_index = _simple_hash((u8 *)&arp->ip_dst, 4); + hash_index = _simple_hash((u8 *)&arp->ip_dst, sizeof(arp->ip_src)); client_info = &(bond_info->rx_hashtbl[hash_index]); - if (client_info->assigned == 1) { + if (client_info->assigned) { if ((client_info->ip_src == arp->ip_src) && (client_info->ip_dst == arp->ip_dst)) { /* the entry is already assigned to this client */ - if (memcmp(arp->mac_dst, mac_bcast, ETH_ALEN)) { /* update mac address from arp */ memcpy(client_info->mac_dst, arp->mac_dst, ETH_ALEN); @@ -710,12 +631,12 @@ } } else { /* the entry is already assigned to some other client, - * move the old client to primary (current_slave) so + * move the old client to primary (curr_active_slave) so * that the new client can be assigned to this entry. */ - if (bond->current_slave && - client_info->slave != bond->current_slave) { - client_info->slave = bond->current_slave; + if (bond->curr_active_slave && + client_info->slave != bond->curr_active_slave) { + client_info->slave = bond->curr_active_slave; rlb_update_client(client_info); } } @@ -736,8 +657,7 @@ if (memcmp(client_info->mac_dst, mac_bcast, ETH_ALEN)) { client_info->ntt = 1; bond->alb_info.rx_ntt = 1; - } - else { + } else { client_info->ntt = 0; } @@ -760,10 +680,9 @@ /* chooses (and returns) transmit channel for arp reply * does not choose channel for other arp types since they are - * sent on the current_slave + * sent on the curr_active_slave */ -static struct slave* -rlb_arp_xmit(struct sk_buff *skb, struct bonding *bond) +static struct slave *rlb_arp_xmit(struct sk_buff *skb, struct bonding *bond) { struct arp_pkt *arp = (struct arp_pkt *)skb->nh.raw; struct slave *tx_slave = NULL; @@ -776,9 +695,8 @@ if (tx_slave) { memcpy(arp->mac_src,tx_slave->dev->dev_addr, ETH_ALEN); } - BOND_PRINT_DBG(("Server sent ARP Reply packet")); + dprintk("Server sent ARP Reply packet\n"); } else if (arp->op_code == __constant_htons(ARPOP_REQUEST)) { - /* Create an entry in the rx_hashtbl for this client as a * place holder. * When the arp reply is received the entry will be updated @@ -797,34 +715,29 @@ * updated with their assigned mac. */ rlb_req_update_subnet_clients(bond, arp->ip_src); - BOND_PRINT_DBG(("Server sent ARP Request packet")); + dprintk("Server sent ARP Request packet\n"); } return tx_slave; } /* Caller must hold bond lock for read */ -static void -rlb_rebalance(struct bonding *bond) +static void rlb_rebalance(struct bonding *bond) { struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond)); - struct slave *assigned_slave = NULL; + struct slave *assigned_slave; + struct rlb_client_info *client_info; + int ntt; u32 hash_index; - struct rlb_client_info *client_info = NULL; - u8 ntt = 0; _lock_rx_hashtbl(bond); - if (bond_info->rx_hashtbl == NULL) { - _unlock_rx_hashtbl(bond); - return; - } - + ntt = 0; hash_index = bond_info->rx_hashtbl_head; for (; hash_index != RLB_NULL_INDEX; hash_index = client_info->next) { client_info = &(bond_info->rx_hashtbl[hash_index]); assigned_slave = rlb_next_rx_slave(bond); - if (assigned_slave && (client_info->slave != assigned_slave)){ + if (assigned_slave && (client_info->slave != assigned_slave)) { client_info->slave = assigned_slave; client_info->ntt = 1; ntt = 1; @@ -839,96 +752,83 @@ } /* Caller must hold rx_hashtbl lock */ -static inline void -rlb_init_table_entry(struct rlb_client_info *entry) +static void rlb_init_table_entry(struct rlb_client_info *entry) { + memset(entry, 0, sizeof(struct rlb_client_info)); entry->next = RLB_NULL_INDEX; entry->prev = RLB_NULL_INDEX; - entry->assigned = 0; - entry->ntt = 0; } -static int -rlb_initialize(struct bonding *bond) +static int rlb_initialize(struct bonding *bond) { struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond)); struct packet_type *pk_type = &(BOND_ALB_INFO(bond).rlb_pkt_type); + int size = RLB_HASH_TABLE_SIZE * sizeof(struct rlb_client_info); int i; - size_t size; spin_lock_init(&(bond_info->rx_hashtbl_lock)); _lock_rx_hashtbl(bond); - if (bond_info->rx_hashtbl != NULL) { - printk (KERN_ERR "%s: RLB hash table is not NULL\n", - bond->device->name); - _unlock_rx_hashtbl(bond); - return -1; - } - size = RLB_HASH_TABLE_SIZE * sizeof(struct rlb_client_info); bond_info->rx_hashtbl = kmalloc(size, GFP_KERNEL); - if (bond_info->rx_hashtbl == NULL) { - printk (KERN_ERR "%s: Failed to allocate" - " RLB hash table\n", bond->device->name); + if (!bond_info->rx_hashtbl) { + printk(KERN_ERR DRV_NAME + ": Error: %s: Failed to allocate RLB hash table\n", + bond->dev->name); _unlock_rx_hashtbl(bond); return -1; } bond_info->rx_hashtbl_head = RLB_NULL_INDEX; - for (i=0; irx_hashtbl + i); } - _unlock_rx_hashtbl(bond); - /* register to receive ARPs */ + _unlock_rx_hashtbl(bond); /*initialize packet type*/ pk_type->type = __constant_htons(ETH_P_ARP); - pk_type->dev = bond->device; + pk_type->dev = bond->dev; pk_type->func = rlb_arp_recv; + /* register to receive ARPs */ dev_add_pack(pk_type); return 0; } -static void -rlb_deinitialize(struct bonding *bond) +static void rlb_deinitialize(struct bonding *bond) { struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond)); dev_remove_pack(&(bond_info->rlb_pkt_type)); _lock_rx_hashtbl(bond); - if (bond_info->rx_hashtbl == NULL) { - _unlock_rx_hashtbl(bond); - return; - } + kfree(bond_info->rx_hashtbl); bond_info->rx_hashtbl = NULL; + _unlock_rx_hashtbl(bond); } /*********************** tlb/rlb shared functions *********************/ -static void -alb_send_learning_packets(struct slave *slave, u8 mac_addr[]) +static void alb_send_learning_packets(struct slave *slave, u8 mac_addr[]) { - struct sk_buff *skb = NULL; struct learning_pkt pkt; - char *data = NULL; + int size = sizeof(struct learning_pkt); int i; - unsigned int size = sizeof(struct learning_pkt); memset(&pkt, 0, size); memcpy(pkt.mac_dst, mac_addr, ETH_ALEN); memcpy(pkt.mac_src, mac_addr, ETH_ALEN); pkt.type = __constant_htons(ETH_P_LOOP); - for (i=0; i < MAX_LP_RETRY; i++) { - skb = NULL; + for (i = 0; i < MAX_LP_RETRY; i++) { + struct sk_buff *skb; + char *data; + skb = dev_alloc_skb(size); if (!skb) { return; @@ -936,28 +836,26 @@ data = skb_put(skb, size); memcpy(data, &pkt, size); + skb->mac.raw = data; skb->nh.raw = data + ETH_HLEN; skb->protocol = pkt.type; skb->priority = TC_PRIO_CONTROL; skb->dev = slave->dev; + dev_queue_xmit(skb); } - } /* hw is a boolean parameter that determines whether we should try and * set the hw address of the device as well as the hw address of the * net_device */ -static int -alb_set_slave_mac_addr(struct slave *slave, u8 addr[], int hw) +static int alb_set_slave_mac_addr(struct slave *slave, u8 addr[], int hw) { - struct net_device *dev = NULL; + struct net_device *dev = slave->dev; struct sockaddr s_addr; - dev = slave->dev; - if (!hw) { memcpy(dev->dev_addr, addr, dev->addr_len); return 0; @@ -968,26 +866,23 @@ memcpy(s_addr.sa_data, addr, dev->addr_len); s_addr.sa_family = dev->type; if (dev->set_mac_address(dev, &s_addr)) { - printk(KERN_DEBUG "bonding: Error: alb_set_slave_mac_addr:" - " dev->set_mac_address of dev %s failed!" - " ALB mode requires that the base driver" - " support setting the hw address also when" - " the network device's interface is open\n", - dev->name); + printk(KERN_ERR DRV_NAME + ": Error: dev->set_mac_address of dev %s failed! ALB " + "mode requires that the base driver support setting " + "the hw address also when the network device's " + "interface is open\n", + dev->name); return -EOPNOTSUPP; } return 0; } -/* Caller must hold bond lock for write or ptrlock for write*/ -static void -alb_swap_mac_addr(struct bonding *bond, - struct slave *slave1, - struct slave *slave2) +/* Caller must hold bond lock for write or curr_slave_lock for write*/ +static void alb_swap_mac_addr(struct bonding *bond, struct slave *slave1, struct slave *slave2) { - u8 tmp_mac_addr[ETH_ALEN]; struct slave *disabled_slave = NULL; - u8 slaves_state_differ; + u8 tmp_mac_addr[ETH_ALEN]; + int slaves_state_differ; slaves_state_differ = (SLAVE_IS_OK(slave1) != SLAVE_IS_OK(slave2)); @@ -1004,8 +899,7 @@ */ rlb_req_update_slave_clients(bond, slave1); } - } - else { + } else { disabled_slave = slave1; } @@ -1017,15 +911,14 @@ */ rlb_req_update_slave_clients(bond, slave2); } - } - else { + } else { disabled_slave = slave2; } if (bond->alb_info.rlb_enabled && slaves_state_differ) { - /* A disabled slave was assigned an active mac addr */ - rlb_teach_disabled_mac_on_primary(bond, - disabled_slave->dev->dev_addr); + /* A disabled slave was assigned an active mac addr */ + rlb_teach_disabled_mac_on_primary(bond, + disabled_slave->dev->dev_addr); } } @@ -1043,10 +936,8 @@ * * Caller must hold bond lock */ -static void -alb_change_hw_addr_on_detach(struct bonding *bond, struct slave *slave) +static void alb_change_hw_addr_on_detach(struct bonding *bond, struct slave *slave) { - struct slave *tmp_slave; int perm_curr_diff; int perm_bond_diff; @@ -1054,20 +945,23 @@ slave->dev->dev_addr, ETH_ALEN); perm_bond_diff = memcmp(slave->perm_hwaddr, - bond->device->dev_addr, + bond->dev->dev_addr, ETH_ALEN); + if (perm_curr_diff && perm_bond_diff) { - tmp_slave = bond_get_first_slave(bond); - while (tmp_slave) { + struct slave *tmp_slave; + int i, found = 0; + + bond_for_each_slave(bond, tmp_slave, i) { if (!memcmp(slave->perm_hwaddr, - tmp_slave->dev->dev_addr, - ETH_ALEN)) { + tmp_slave->dev->dev_addr, + ETH_ALEN)) { + found = 1; break; } - tmp_slave = bond_get_next_slave(bond, tmp_slave); } - if (tmp_slave) { + if (found) { alb_swap_mac_addr(bond, slave, tmp_slave); } } @@ -1098,10 +992,11 @@ * caller must hold the bond lock for write since the mac addresses are compared * and may be swapped. */ -static int -alb_handle_addr_collision_on_attach(struct bonding *bond, struct slave *slave) +static int alb_handle_addr_collision_on_attach(struct bonding *bond, struct slave *slave) { - struct slave *tmp_slave1, *tmp_slave2; + struct slave *tmp_slave1, *tmp_slave2, *free_mac_slave; + struct slave *has_bond_addr = bond->curr_active_slave; + int i, j, found = 0; if (bond->slave_cnt == 0) { /* this is the first slave */ @@ -1112,65 +1007,78 @@ * check uniqueness of slave's mac address against the other * slaves in the bond. */ - if (memcmp(slave->perm_hwaddr, bond->device->dev_addr, ETH_ALEN)) { - tmp_slave1 = bond_get_first_slave(bond); - for (; tmp_slave1; tmp_slave1 = bond_get_next_slave(bond, tmp_slave1)) { + if (memcmp(slave->perm_hwaddr, bond->dev->dev_addr, ETH_ALEN)) { + bond_for_each_slave(bond, tmp_slave1, i) { if (!memcmp(tmp_slave1->dev->dev_addr, slave->dev->dev_addr, ETH_ALEN)) { + found = 1; break; } } - if (tmp_slave1) { + + if (found) { /* a slave was found that is using the mac address * of the new slave */ - printk(KERN_ERR "bonding: Warning: the hw address " - "of slave %s is not unique - cannot enslave it!" - , slave->dev->name); + printk(KERN_ERR DRV_NAME + ": Error: the hw address of slave %s is not " + "unique - cannot enslave it!", + slave->dev->name); return -EINVAL; } + return 0; } - /* the slave's address is equal to the address of the bond - * search for a spare address in the bond for this slave. + /* The slave's address is equal to the address of the bond. + * Search for a spare address in the bond for this slave. */ - tmp_slave1 = bond_get_first_slave(bond); - for (; tmp_slave1; tmp_slave1 = bond_get_next_slave(bond, tmp_slave1)) { - - tmp_slave2 = bond_get_first_slave(bond); - for (; tmp_slave2; tmp_slave2 = bond_get_next_slave(bond, tmp_slave2)) { + free_mac_slave = NULL; + bond_for_each_slave(bond, tmp_slave1, i) { + found = 0; + bond_for_each_slave(bond, tmp_slave2, j) { if (!memcmp(tmp_slave1->perm_hwaddr, tmp_slave2->dev->dev_addr, ETH_ALEN)) { - + found = 1; break; } } - if (!tmp_slave2) { + if (!found) { /* no slave has tmp_slave1's perm addr * as its curr addr */ + free_mac_slave = tmp_slave1; break; } + + if (!has_bond_addr) { + if (!memcmp(tmp_slave1->dev->dev_addr, + bond->dev->dev_addr, + ETH_ALEN)) { + + has_bond_addr = tmp_slave1; + } + } } - if (tmp_slave1) { - alb_set_slave_mac_addr(slave, tmp_slave1->perm_hwaddr, + if (free_mac_slave) { + alb_set_slave_mac_addr(slave, free_mac_slave->perm_hwaddr, bond->alb_info.rlb_enabled); - printk(KERN_WARNING "bonding: Warning: the hw address " - "of slave %s is in use by the bond; " - "giving it the hw address of %s\n", - slave->dev->name, tmp_slave1->dev->name); - } else { - printk(KERN_CRIT "bonding: Error: the hw address " - "of slave %s is in use by the bond; " - "couldn't find a slave with a free hw " - "address to give it (this should not have " - "happened)\n", slave->dev->name); + printk(KERN_WARNING DRV_NAME + ": Warning: the hw address of slave %s is in use by " + "the bond; giving it the hw address of %s\n", + slave->dev->name, free_mac_slave->dev->name); + + } else if (has_bond_addr) { + printk(KERN_ERR DRV_NAME + ": Error: the hw address of slave %s is in use by the " + "bond; couldn't find a slave with a free hw address to " + "give it (this should not have happened)\n", + slave->dev->name); return -EFAULT; } @@ -1188,37 +1096,36 @@ * * For each slave, this function sets the interface to the new address and then * changes its dev_addr field to its previous value. - * + * * Unwinding assumes bond's mac address has not yet changed. */ -static inline int -alb_set_mac_address(struct bonding *bond, void *addr) +static int alb_set_mac_address(struct bonding *bond, void *addr) { struct sockaddr sa; - struct slave *slave; + struct slave *slave, *stop_at; char tmp_addr[ETH_ALEN]; - int error; + int res; + int i; if (bond->alb_info.rlb_enabled) { return 0; } - slave = bond_get_first_slave(bond); - for (; slave; slave = bond_get_next_slave(bond, slave)) { + bond_for_each_slave(bond, slave, i) { if (slave->dev->set_mac_address == NULL) { - error = -EOPNOTSUPP; + res = -EOPNOTSUPP; goto unwind; } /* save net_device's current hw address */ memcpy(tmp_addr, slave->dev->dev_addr, ETH_ALEN); - error = slave->dev->set_mac_address(slave->dev, addr); + res = slave->dev->set_mac_address(slave->dev, addr); /* restore net_device's hw address */ memcpy(slave->dev->dev_addr, tmp_addr, ETH_ALEN); - if (error) { + if (res) { goto unwind; } } @@ -1226,22 +1133,23 @@ return 0; unwind: - memcpy(sa.sa_data, bond->device->dev_addr, bond->device->addr_len); - sa.sa_family = bond->device->type; - slave = bond_get_first_slave(bond); - for (; slave; slave = bond_get_next_slave(bond, slave)) { + memcpy(sa.sa_data, bond->dev->dev_addr, bond->dev->addr_len); + sa.sa_family = bond->dev->type; + + /* unwind from head to the slave that failed */ + stop_at = slave; + bond_for_each_slave_from_to(bond, slave, i, bond->first_slave, stop_at) { memcpy(tmp_addr, slave->dev->dev_addr, ETH_ALEN); slave->dev->set_mac_address(slave->dev, &sa); memcpy(slave->dev->dev_addr, tmp_addr, ETH_ALEN); } - return error; + return res; } /************************ exported alb funcions ************************/ -int -bond_alb_initialize(struct bonding *bond, int rlb_enabled) +int bond_alb_initialize(struct bonding *bond, int rlb_enabled) { int res; @@ -1263,8 +1171,7 @@ return 0; } -void -bond_alb_deinitialize(struct bonding *bond) +void bond_alb_deinitialize(struct bonding *bond) { struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond)); @@ -1275,49 +1182,38 @@ } } -int -bond_alb_xmit(struct sk_buff *skb, struct net_device *dev) +int bond_alb_xmit(struct sk_buff *skb, struct net_device *bond_dev) { - struct bonding *bond = (struct bonding *) dev->priv; - struct ethhdr *eth_data = (struct ethhdr *)skb->data; + struct bonding *bond = bond_dev->priv; + struct ethhdr *eth_data = (struct ethhdr *)skb->mac.raw = skb->data; struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond)); struct slave *tx_slave = NULL; - char do_tx_balance = 1; + static u32 ip_bcast = 0xffffffff; int hash_size = 0; + int do_tx_balance = 1; u32 hash_index = 0; u8 *hash_start = NULL; - u8 mac_bcast[ETH_ALEN] = {0xff,0xff,0xff,0xff,0xff,0xff}; - if (!IS_UP(dev)) { /* bond down */ - dev_kfree_skb(skb); - return 0; - } - - /* make sure that the current_slave and the slaves list do + /* make sure that the curr_active_slave and the slaves list do * not change during tx */ read_lock(&bond->lock); + read_lock(&bond->curr_slave_lock); - if (bond->slave_cnt == 0) { - /* no suitable interface, frame not sent */ - dev_kfree_skb(skb); - read_unlock(&bond->lock); - return 0; + if (!BOND_IS_OK(bond)) { + goto free_out; } - read_lock(&bond->ptrlock); - switch (ntohs(skb->protocol)) { case ETH_P_IP: if ((memcmp(eth_data->h_dest, mac_bcast, ETH_ALEN) == 0) || - (skb->nh.iph->daddr == 0xffffffff)) { + (skb->nh.iph->daddr == ip_bcast)) { do_tx_balance = 0; break; } hash_start = (char*)&(skb->nh.iph->daddr); - hash_size = 4; + hash_size = sizeof(skb->nh.iph->daddr); break; - case ETH_P_IPV6: if (memcmp(eth_data->h_dest, mac_bcast, ETH_ALEN) == 0) { do_tx_balance = 0; @@ -1325,9 +1221,8 @@ } hash_start = (char*)&(skb->nh.ipv6h->daddr); - hash_size = 16; + hash_size = sizeof(skb->nh.ipv6h->daddr); break; - case ETH_P_IPX: if (ipx_hdr(skb)->ipx_checksum != __constant_htons(IPX_NO_CHECKSUM)) { @@ -1336,8 +1231,7 @@ break; } - if (ipx_hdr(skb)->ipx_type != - __constant_htons(IPX_TYPE_NCP)) { + if (ipx_hdr(skb)->ipx_type != IPX_TYPE_NCP) { /* The only protocol worth balancing in * this family since it has an "ARP" like * mechanism @@ -1349,14 +1243,12 @@ hash_start = (char*)eth_data->h_dest; hash_size = ETH_ALEN; break; - case ETH_P_ARP: do_tx_balance = 0; if (bond_info->rlb_enabled) { tx_slave = rlb_arp_xmit(skb, bond); } break; - default: do_tx_balance = 0; break; @@ -1369,16 +1261,16 @@ if (!tx_slave) { /* unbalanced or unassigned, send through primary */ - tx_slave = bond->current_slave; + tx_slave = bond->curr_active_slave; bond_info->unbalanced_load += skb->len; } if (tx_slave && SLAVE_IS_OK(tx_slave)) { skb->dev = tx_slave->dev; - if (tx_slave != bond->current_slave) { + if (tx_slave != bond->curr_active_slave) { memcpy(eth_data->h_source, - tx_slave->dev->dev_addr, - ETH_ALEN); + tx_slave->dev->dev_addr, + ETH_ALEN); } dev_queue_xmit(skb); } else { @@ -1386,26 +1278,35 @@ if (tx_slave) { tlb_clear_slave(bond, tx_slave, 0); } - dev_kfree_skb(skb); + goto free_out; } - read_unlock(&bond->ptrlock); +out: + read_unlock(&bond->curr_slave_lock); read_unlock(&bond->lock); return 0; + +free_out: + dev_kfree_skb(skb); + goto out; } -void -bond_alb_monitor(struct bonding *bond) +void bond_alb_monitor(struct bonding *bond) { struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond)); - struct slave *slave = NULL; + struct slave *slave; + int i; read_lock(&bond->lock); - if ((bond->slave_cnt == 0) || !(bond->device->flags & IFF_UP)) { + if (bond->kill_timers) { + goto out; + } + + if (bond->slave_cnt == 0) { bond_info->tx_rebalance_counter = 0; bond_info->lp_counter = 0; - goto out; + goto re_arm; } bond_info->tx_rebalance_counter++; @@ -1413,51 +1314,53 @@ /* send learning packets */ if (bond_info->lp_counter >= BOND_ALB_LP_TICKS) { - /* change of current_slave involves swapping of mac addresses. + /* change of curr_active_slave involves swapping of mac addresses. * in order to avoid this swapping from happening while - * sending the learning packets, the ptrlock must be held for + * sending the learning packets, the curr_slave_lock must be held for * read. */ - read_lock(&bond->ptrlock); - slave = bond_get_first_slave(bond); - while (slave) { + read_lock(&bond->curr_slave_lock); + + bond_for_each_slave(bond, slave, i) { alb_send_learning_packets(slave,slave->dev->dev_addr); - slave = bond_get_next_slave(bond, slave); } - read_unlock(&bond->ptrlock); + + read_unlock(&bond->curr_slave_lock); bond_info->lp_counter = 0; } /* rebalance tx traffic */ if (bond_info->tx_rebalance_counter >= BOND_TLB_REBALANCE_TICKS) { - read_lock(&bond->ptrlock); - slave = bond_get_first_slave(bond); - while (slave) { + + read_lock(&bond->curr_slave_lock); + + bond_for_each_slave(bond, slave, i) { tlb_clear_slave(bond, slave, 1); - if (slave == bond->current_slave) { + if (slave == bond->curr_active_slave) { SLAVE_TLB_INFO(slave).load = bond_info->unbalanced_load / BOND_TLB_REBALANCE_INTERVAL; bond_info->unbalanced_load = 0; } - slave = bond_get_next_slave(bond, slave); } - read_unlock(&bond->ptrlock); + + read_unlock(&bond->curr_slave_lock); + bond_info->tx_rebalance_counter = 0; } /* handle rlb stuff */ if (bond_info->rlb_enabled) { /* the following code changes the promiscuity of the - * the current_slave. It needs to be locked with a + * the curr_active_slave. It needs to be locked with a * write lock to protect from other code that also * sets the promiscuity. */ - write_lock(&bond->ptrlock); + write_lock(&bond->curr_slave_lock); + if (bond_info->primary_is_promisc && - (++bond_info->rlb_promisc_timeout_counter >= - RLB_PROMISC_TIMEOUT)) { + (++bond_info->rlb_promisc_timeout_counter >= RLB_PROMISC_TIMEOUT)) { bond_info->rlb_promisc_timeout_counter = 0; @@ -1465,12 +1368,13 @@ * because a slave was disabled then * it can now leave promiscuous mode. */ - dev_set_promiscuity(bond->current_slave->dev, -1); + dev_set_promiscuity(bond->curr_active_slave->dev, -1); bond_info->primary_is_promisc = 0; } - write_unlock(&bond->ptrlock); - if (bond_info->rlb_rebalance == 1) { + write_unlock(&bond->curr_slave_lock); + + if (bond_info->rlb_rebalance) { bond_info->rlb_rebalance = 0; rlb_rebalance(bond); } @@ -1490,28 +1394,23 @@ } } +re_arm: + mod_timer(&(bond_info->alb_timer), jiffies + alb_delta_in_ticks); out: read_unlock(&bond->lock); - - if (bond->device->flags & IFF_UP) { - /* re-arm the timer */ - mod_timer(&(bond_info->alb_timer), - jiffies + (HZ/ALB_TIMER_TICKS_PER_SEC)); - } } -/* assumption: called before the slave is attched to the bond +/* assumption: called before the slave is attached to the bond * and not locked by the bond lock */ -int -bond_alb_init_slave(struct bonding *bond, struct slave *slave) +int bond_alb_init_slave(struct bonding *bond, struct slave *slave) { - int err = 0; + int res; - err = alb_set_slave_mac_addr(slave, slave->perm_hwaddr, + res = alb_set_slave_mac_addr(slave, slave->perm_hwaddr, bond->alb_info.rlb_enabled); - if (err) { - return err; + if (res) { + return res; } /* caller must hold the bond lock for write since the mac addresses @@ -1519,12 +1418,12 @@ */ write_lock_bh(&bond->lock); - err = alb_handle_addr_collision_on_attach(bond, slave); + res = alb_handle_addr_collision_on_attach(bond, slave); write_unlock_bh(&bond->lock); - if (err) { - return err; + if (res) { + return res; } tlb_init_slave(slave); @@ -1540,8 +1439,7 @@ } /* Caller must hold bond lock for write */ -void -bond_alb_deinit_slave(struct bonding *bond, struct slave *slave) +void bond_alb_deinit_slave(struct bonding *bond, struct slave *slave) { if (bond->slave_cnt > 1) { alb_change_hw_addr_on_detach(bond, slave); @@ -1556,9 +1454,7 @@ } /* Caller must hold bond lock for read */ -void -bond_alb_handle_link_change(struct bonding *bond, struct slave *slave, - char link) +void bond_alb_handle_link_change(struct bonding *bond, struct slave *slave, char link) { struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond)); @@ -1582,109 +1478,111 @@ } /** - * bond_alb_assign_current_slave - assign new current_slave + * bond_alb_handle_active_change - assign new curr_active_slave * @bond: our bonding struct * @new_slave: new slave to assign * - * Set the bond->current_slave to @new_slave and handle + * Set the bond->curr_active_slave to @new_slave and handle * mac address swapping and promiscuity changes as needed. * - * Caller must hold bond ptrlock for write (or bond lock for write) + * Caller must hold bond curr_slave_lock for write (or bond lock for write) */ -void -bond_alb_assign_current_slave(struct bonding *bond, struct slave *new_slave) +void bond_alb_handle_active_change(struct bonding *bond, struct slave *new_slave) { - struct slave *swap_slave = bond->current_slave; + struct slave *swap_slave; + int i; - if (bond->current_slave == new_slave) { + if (bond->curr_active_slave == new_slave) { return; } - if (bond->current_slave && bond->alb_info.primary_is_promisc) { - dev_set_promiscuity(bond->current_slave->dev, -1); + if (bond->curr_active_slave && bond->alb_info.primary_is_promisc) { + dev_set_promiscuity(bond->curr_active_slave->dev, -1); bond->alb_info.primary_is_promisc = 0; bond->alb_info.rlb_promisc_timeout_counter = 0; } - bond->current_slave = new_slave; + swap_slave = bond->curr_active_slave; + bond->curr_active_slave = new_slave; if (!new_slave || (bond->slave_cnt == 0)) { return; } - /* set the new current_slave to the bonds mac address - * i.e. swap mac addresses of old current_slave and new current_slave + /* set the new curr_active_slave to the bonds mac address + * i.e. swap mac addresses of old curr_active_slave and new curr_active_slave */ if (!swap_slave) { + struct slave *tmp_slave; /* find slave that is holding the bond's mac address */ - swap_slave = bond_get_first_slave(bond); - while (swap_slave) { - if (!memcmp(swap_slave->dev->dev_addr, - bond->device->dev_addr, ETH_ALEN)) { + bond_for_each_slave(bond, tmp_slave, i) { + if (!memcmp(tmp_slave->dev->dev_addr, + bond->dev->dev_addr, ETH_ALEN)) { + swap_slave = tmp_slave; break; } - swap_slave = bond_get_next_slave(bond, swap_slave); } } - /* current_slave must be set before calling alb_swap_mac_addr */ + /* curr_active_slave must be set before calling alb_swap_mac_addr */ if (swap_slave) { /* swap mac address */ alb_swap_mac_addr(bond, swap_slave, new_slave); } else { /* set the new_slave to the bond mac address */ - alb_set_slave_mac_addr(new_slave, bond->device->dev_addr, + alb_set_slave_mac_addr(new_slave, bond->dev->dev_addr, bond->alb_info.rlb_enabled); /* fasten bond mac on new current slave */ - alb_send_learning_packets(new_slave, bond->device->dev_addr); + alb_send_learning_packets(new_slave, bond->dev->dev_addr); } } -int -bond_alb_set_mac_address(struct net_device *dev, void *addr) +int bond_alb_set_mac_address(struct net_device *bond_dev, void *addr) { - struct bonding *bond = dev->priv; + struct bonding *bond = bond_dev->priv; struct sockaddr *sa = addr; - struct slave *swap_slave = NULL; - int error = 0; + struct slave *slave, *swap_slave; + int res; + int i; if (!is_valid_ether_addr(sa->sa_data)) { return -EADDRNOTAVAIL; } - error = alb_set_mac_address(bond, addr); - if (error) { - return error; + res = alb_set_mac_address(bond, addr); + if (res) { + return res; } - memcpy(dev->dev_addr, sa->sa_data, dev->addr_len); + memcpy(bond_dev->dev_addr, sa->sa_data, bond_dev->addr_len); - /* If there is no current_slave there is nothing else to do. + /* If there is no curr_active_slave there is nothing else to do. * Otherwise we'll need to pass the new address to it and handle * duplications. */ - if (bond->current_slave == NULL) { + if (!bond->curr_active_slave) { return 0; } - swap_slave = bond_get_first_slave(bond); - while (swap_slave) { - if (!memcmp(swap_slave->dev->dev_addr, dev->dev_addr, ETH_ALEN)) { + swap_slave = NULL; + + bond_for_each_slave(bond, slave, i) { + if (!memcmp(slave->dev->dev_addr, bond_dev->dev_addr, ETH_ALEN)) { + swap_slave = slave; break; } - swap_slave = bond_get_next_slave(bond, swap_slave); } if (swap_slave) { - alb_swap_mac_addr(bond, swap_slave, bond->current_slave); + alb_swap_mac_addr(bond, swap_slave, bond->curr_active_slave); } else { - alb_set_slave_mac_addr(bond->current_slave, dev->dev_addr, + alb_set_slave_mac_addr(bond->curr_active_slave, bond_dev->dev_addr, bond->alb_info.rlb_enabled); - alb_send_learning_packets(bond->current_slave, dev->dev_addr); + alb_send_learning_packets(bond->curr_active_slave, bond_dev->dev_addr); if (bond->alb_info.rlb_enabled) { /* inform clients mac address has changed */ - rlb_req_update_slave_clients(bond, bond->current_slave); + rlb_req_update_slave_clients(bond, bond->curr_active_slave); } } diff -Nru a/drivers/net/bonding/bond_alb.h b/drivers/net/bonding/bond_alb.h --- a/drivers/net/bonding/bond_alb.h Thu Jan 22 18:59:24 2004 +++ b/drivers/net/bonding/bond_alb.h Thu Jan 22 18:59:24 2004 @@ -1,5 +1,5 @@ /* - * Copyright(c) 1999 - 2003 Intel Corporation. All rights reserved. + * Copyright(c) 1999 - 2004 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -24,6 +24,9 @@ * 2003/08/06 - Amir Noam * - Add support for setting bond's MAC address with special * handling required for ALB/TLB. + * + * 2003/12/01 - Shmulik Hen + * - Code cleanup and style changes */ #ifndef __BOND_ALB_H__ @@ -126,10 +129,10 @@ int bond_alb_init_slave(struct bonding *bond, struct slave *slave); void bond_alb_deinit_slave(struct bonding *bond, struct slave *slave); void bond_alb_handle_link_change(struct bonding *bond, struct slave *slave, char link); -void bond_alb_assign_current_slave(struct bonding *bond, struct slave *new_slave); -int bond_alb_xmit(struct sk_buff *skb, struct net_device *dev); +void bond_alb_handle_active_change(struct bonding *bond, struct slave *new_slave); +int bond_alb_xmit(struct sk_buff *skb, struct net_device *bond_dev); void bond_alb_monitor(struct bonding *bond); -int bond_alb_set_mac_address(struct net_device *dev, void *addr); +int bond_alb_set_mac_address(struct net_device *bond_dev, void *addr); #endif /* __BOND_ALB_H__ */ diff -Nru a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c --- a/drivers/net/bonding/bond_main.c Thu Jan 22 18:59:26 2004 +++ b/drivers/net/bonding/bond_main.c Thu Jan 22 18:59:26 2004 @@ -1,7 +1,7 @@ /* * originally based on the dummy device. * - * Copyright 1999, Thomas Davis, tadavis@lbl.gov. + * Copyright 1999, Thomas Davis, tadavis@lbl.gov. * Licensed under the GPL. Based on dummy.c, and eql.c devices. * * bonding.c: an Ethernet Bonding driver @@ -15,9 +15,9 @@ * * How it works: * ifconfig bond0 ipaddress netmask up - * will setup a network device, with an ip address. No mac address - * will be assigned at this time. The hw mac address will come from - * the first slave bonded to the channel. All slaves will then use + * will setup a network device, with an ip address. No mac address + * will be assigned at this time. The hw mac address will come from + * the first slave bonded to the channel. All slaves will then use * this hw mac address. * * ifconfig bond0 down @@ -26,7 +26,7 @@ * ifenslave bond0 eth0 * will attach eth0 to bond0 as a slave. eth0 hw mac address will either * a: be used as initial mac address - * b: if a hw mac address already is there, eth0's hw mac address + * b: if a hw mac address already is there, eth0's hw mac address * will then be set from bond0. * * v0.1 - first working version. @@ -93,14 +93,14 @@ * * 2001/4/5 - Chad N. Tindel * - Ported to 2.4 Kernel - * + * * 2001/5/2 - Jeffrey E. Mast * - When a device is detached from a bond, the slave device is no longer * left thinking that is has a master. * * 2001/5/16 - Jeffrey E. Mast - * - memset did not appropriately initialized the bond rw_locks. Used - * rwlock_init to initialize to unlocked state to prevent deadlock when + * - memset did not appropriately initialized the bond rw_locks. Used + * rwlock_init to initialize to unlocked state to prevent deadlock when * first attempting a lock * - Called SET_MODULE_OWNER for bond device * @@ -119,7 +119,7 @@ * * 2001/6/01 - Chad N. Tindel * - Added /proc support for getting bond and slave information. - * Information is in /proc/net//info. + * Information is in /proc/net//info. * - Changed the locking when calling bond_close to prevent deadlock. * * 2001/8/05 - Janice Girouard @@ -144,8 +144,8 @@ * but only for an up link. * * 2001/9/20 - Chad N. Tindel - * - Add the device field to bonding_t. Previously the net_device - * corresponding to a bond wasn't available from the bonding_t + * - Add the device field to bonding_t. Previously the net_device + * corresponding to a bond wasn't available from the bonding_t * structure. * * 2001/9/25 - Janice Girouard @@ -155,10 +155,10 @@ * - Various memory leak fixes * * 2001/11/5 - Mark Huth - * - Don't take rtnl lock in bond_mii_monitor as it deadlocks under - * certain hotswap conditions. + * - Don't take rtnl lock in bond_mii_monitor as it deadlocks under + * certain hotswap conditions. * Note: this same change may be required in bond_arp_monitor ??? - * - Remove possibility of calling bond_sethwaddr with NULL slave_dev ptr + * - Remove possibility of calling bond_sethwaddr with NULL slave_dev ptr * - Handle hot swap ethernet interface deregistration events to remove * kernel oops following hot swap of enslaved interface * @@ -222,23 +222,23 @@ * - fix deletion of multicast groups after unloading module * * 2002/11/06 - Kameshwara Rayaprolu - * - Changes to prevent panic from closing the device twice; if we close - * the device in bond_release, we must set the original_flags to down + * - Changes to prevent panic from closing the device twice; if we close + * the device in bond_release, we must set the original_flags to down * so it won't be closed again by the network layer. * * 2002/11/07 - Tony Cureington * - Fix arp_target_hw_addr memory leak - * - Created activebackup_arp_monitor function to handle arp monitoring - * in active backup mode - the bond_arp_monitor had several problems... - * such as allowing slaves to tx arps sequentially without any delay + * - Created activebackup_arp_monitor function to handle arp monitoring + * in active backup mode - the bond_arp_monitor had several problems... + * such as allowing slaves to tx arps sequentially without any delay * for a response * - Renamed bond_arp_monitor to loadbalance_arp_monitor and re-wrote * this function to just handle arp monitoring in load-balancing mode; * it is a lot more compact now - * - Changes to ensure one and only one slave transmits in active-backup + * - Changes to ensure one and only one slave transmits in active-backup * mode - * - Robustesize parameters; warn users about bad combinations of - * parameters; also if miimon is specified and a network driver does + * - Robustesize parameters; warn users about bad combinations of + * parameters; also if miimon is specified and a network driver does * not support MII or ETHTOOL, inform the user of this * - Changes to support link_failure_count when in arp monitoring mode * - Fix up/down delay reported in /proc @@ -248,7 +248,7 @@ * * 2002/11/16 - Laurent Deniel * - fix multicast handling in activebackup_arp_monitor - * - remove one unnecessary and confusing current_slave == slave test + * - remove one unnecessary and confusing curr_active_slave == slave test * in activebackup_arp_monitor * * 2002/11/17 - Laurent Deniel @@ -267,7 +267,7 @@ * One change: an invalid choice will cause module load failure, * rather than the previous behavior of just picking one. * - Minor cleanups; got rid of dup ctype stuff, atoi function - * + * * 2003/02/07 - Jay Vosburgh * - Added use_carrier module parameter that causes miimon to * use netif_carrier_ok() test instead of MII/ETHTOOL ioctls. @@ -330,7 +330,7 @@ * new/old ifenslave and new/old bonding. * * 2003/05/01 - Shmulik Hen - * - Fixed bug in bond_release_all(): save old value of current_slave + * - Fixed bug in bond_release_all(): save old value of curr_active_slave * before setting it to NULL. * - Changed driver versioning scheme to include version number instead * of release date (that is already in another field). There are 3 @@ -358,7 +358,7 @@ * * 2003/05/01 - Shmulik Hen * - Added support for Transmit load balancing mode. - * - Concentrate all assignments of current_slave to a single point + * - Concentrate all assignments of curr_active_slave to a single point * so specific modes can take actions when the primary adapter is * changed. * - Take the updelay parameter into consideration during bond_enslave @@ -426,8 +426,45 @@ * - Convert /proc to seq_file interface. * Change /proc/net/bondX/info to /proc/net/bonding/bondX. * Set version to 2.4.1. + * + * 2003/11/20 - Amir Noam + * - Fix /proc creation/destruction. + * + * 2003/12/01 - Shmulik Hen + * - Massive cleanup - Set version to 2.5.0 + * Code changes: + * o Consolidate format of prints and debug prints. + * o Remove bonding_t/slave_t typedefs and consolidate all casts. + * o Remove dead code and unnecessary checks. + * o Consolidate starting/stopping timers. + * o Consolidate handling of primary module param throughout the code. + * o Removed multicast module param support - all settings are done + * according to mode. + * o Slave list iteration - bond is no longer part of the list, + * added cyclic list iteration macros. + * o Consolidate error handling in all xmit functions. + * Style changes: + * o Consolidate function naming and declarations. + * o Consolidate function params and local variables names. + * o Consolidate return values. + * o Consolidate curly braces. + * o Consolidate conditionals format. + * o Change struct member names and types. + * o Chomp trailing spaces, remove empty lines, fix indentations. + * o Re-organize code according to context. + * + * 2003/12/30 - Amir Noam + * - Fixed: Cannot remove and re-enslave the original active slave. + * - Fixed: Releasing the original active slave causes mac address duplication. + * - Add support for slaves that use ethtool_ops. + * Set version to 2.5.3. + * + * 2004/01/05 - Amir Noam + * - Save bonding parameters per bond instead of using the global values. */ +//#define BONDING_DEBUG 1 + #include #include #include @@ -452,7 +489,6 @@ #include #include #include - #include #include #include @@ -461,58 +497,71 @@ #include #include #include - -#include #include #include #include #include #include +#include #include "bonding.h" #include "bond_3ad.h" #include "bond_alb.h" -#define DRV_VERSION "2.4.1" -#define DRV_RELDATE "September 15, 2003" -#define DRV_NAME "bonding" -#define DRV_DESCRIPTION "Ethernet Channel Bonding Driver" - -static const char *version = -DRV_NAME ".c:v" DRV_VERSION " (" DRV_RELDATE ")\n"; +/*---------------------------- Module parameters ----------------------------*/ /* monitor all links that often (in milliseconds). <=0 disables monitoring */ -#ifndef BOND_LINK_MON_INTERV #define BOND_LINK_MON_INTERV 0 -#endif - -#ifndef BOND_LINK_ARP_INTERV #define BOND_LINK_ARP_INTERV 0 -#endif -#ifndef MAX_ARP_IP_TARGETS -#define MAX_ARP_IP_TARGETS 16 -#endif +static int max_bonds = BOND_DEFAULT_MAX_BONDS; +static int miimon = BOND_LINK_MON_INTERV; +static int updelay = 0; +static int downdelay = 0; +static int use_carrier = 1; +static char *mode = NULL; +static char *primary = NULL; +static char *lacp_rate = NULL; +static int arp_interval = BOND_LINK_ARP_INTERV; +static char *arp_ip_target[BOND_MAX_ARP_TARGETS] = { NULL, }; + +MODULE_PARM(max_bonds, "i"); +MODULE_PARM_DESC(max_bonds, "Max number of bonded devices"); +MODULE_PARM(miimon, "i"); +MODULE_PARM_DESC(miimon, "Link check interval in milliseconds"); +MODULE_PARM(updelay, "i"); +MODULE_PARM_DESC(updelay, "Delay before considering link up, in milliseconds"); +MODULE_PARM(downdelay, "i"); +MODULE_PARM_DESC(downdelay, "Delay before considering link down, in milliseconds"); +MODULE_PARM(use_carrier, "i"); +MODULE_PARM_DESC(use_carrier, "Use netif_carrier_ok (vs MII ioctls) in miimon; 0 for off, 1 for on (default)"); +MODULE_PARM(mode, "s"); +MODULE_PARM_DESC(mode, "Mode of operation : 0 for round robin, 1 for active-backup, 2 for xor"); +MODULE_PARM(primary, "s"); +MODULE_PARM_DESC(primary, "Primary network device to use"); +MODULE_PARM(lacp_rate, "s"); +MODULE_PARM_DESC(lacp_rate, "LACPDU tx rate to request from 802.3ad partner (slow/fast)"); +MODULE_PARM(arp_interval, "i"); +MODULE_PARM_DESC(arp_interval, "arp interval in milliseconds"); +MODULE_PARM(arp_ip_target, "1-" __MODULE_STRING(BOND_MAX_ARP_TARGETS) "s"); +MODULE_PARM_DESC(arp_ip_target, "arp targets in n.n.n.n form"); -#define USES_PRIMARY(mode) \ - (((mode) == BOND_MODE_ACTIVEBACKUP) || \ - ((mode) == BOND_MODE_TLB) || \ - ((mode) == BOND_MODE_ALB)) +/*----------------------------- Global variables ----------------------------*/ -struct bond_parm_tbl { - char *modename; - int mode; -}; +static const char *version = + DRV_DESCRIPTION ": v" DRV_VERSION " (" DRV_RELDATE ")\n"; -static int arp_interval = BOND_LINK_ARP_INTERV; -static char *arp_ip_target[MAX_ARP_IP_TARGETS] = { NULL, }; -static u32 arp_target[MAX_ARP_IP_TARGETS] = { 0, } ; -static int arp_ip_count = 0; -static u32 my_ip = 0; -char *arp_target_hw_addr = NULL; +static LIST_HEAD(bond_dev_list); -static char *primary= NULL; +#ifdef CONFIG_PROC_FS +static struct proc_dir_entry *bond_proc_dir = NULL; +#endif -static int app_abi_ver = 0; +static u32 arp_target[BOND_MAX_ARP_TARGETS] = { 0, } ; +static int arp_ip_count = 0; +static u32 my_ip = 0; +static int bond_mode = BOND_MODE_ROUNDROBIN; +static int lacp_fast = 0; +static int app_abi_ver = 0; static int orig_app_abi_ver = -1; /* This is used to save the first ABI version * we receive from the application. Once set, * it won't be changed, and the module will @@ -521,14 +570,16 @@ * another ABI version. */ -static int max_bonds = BOND_DEFAULT_MAX_BONDS; -static int miimon = BOND_LINK_MON_INTERV; -static int use_carrier = 1; -static int bond_mode = BOND_MODE_ROUNDROBIN; -static int updelay = 0; -static int downdelay = 0; +struct bond_parm_tbl { + char *modename; + int mode; +}; -static char *mode = NULL; +static struct bond_parm_tbl bond_lacp_tbl[] = { +{ "slow", AD_LACP_SLOW}, +{ "fast", AD_LACP_FAST}, +{ NULL, -1}, +}; static struct bond_parm_tbl bond_mode_tbl[] = { { "balance-rr", BOND_MODE_ROUNDROBIN}, @@ -541,103 +592,15 @@ { NULL, -1}, }; -static int multicast_mode = BOND_MULTICAST_ALL; -static char *multicast = NULL; +/*-------------------------- Forward declarations ---------------------------*/ -static struct bond_parm_tbl bond_mc_tbl[] = { -{ "disabled", BOND_MULTICAST_DISABLED}, -{ "active", BOND_MULTICAST_ACTIVE}, -{ "all", BOND_MULTICAST_ALL}, -{ NULL, -1}, -}; - -static int lacp_fast = 0; -static char *lacp_rate = NULL; - -static struct bond_parm_tbl bond_lacp_tbl[] = { -{ "slow", AD_LACP_SLOW}, -{ "fast", AD_LACP_FAST}, -{ NULL, -1}, -}; - -static LIST_HEAD(bond_dev_list); -#ifdef CONFIG_PROC_FS -static struct proc_dir_entry *bond_proc_dir = NULL; -#endif - -MODULE_PARM(max_bonds, "i"); -MODULE_PARM_DESC(max_bonds, "Max number of bonded devices"); -MODULE_PARM(miimon, "i"); -MODULE_PARM_DESC(miimon, "Link check interval in milliseconds"); -MODULE_PARM(use_carrier, "i"); -MODULE_PARM_DESC(use_carrier, "Use netif_carrier_ok (vs MII ioctls) in miimon; 0 for off, 1 for on (default)"); -MODULE_PARM(mode, "s"); -MODULE_PARM_DESC(mode, "Mode of operation : 0 for round robin, 1 for active-backup, 2 for xor"); -MODULE_PARM(arp_interval, "i"); -MODULE_PARM_DESC(arp_interval, "arp interval in milliseconds"); -MODULE_PARM(arp_ip_target, "1-" __MODULE_STRING(MAX_ARP_IP_TARGETS) "s"); -MODULE_PARM_DESC(arp_ip_target, "arp targets in n.n.n.n form"); -MODULE_PARM(updelay, "i"); -MODULE_PARM_DESC(updelay, "Delay before considering link up, in milliseconds"); -MODULE_PARM(downdelay, "i"); -MODULE_PARM_DESC(downdelay, "Delay before considering link down, in milliseconds"); -MODULE_PARM(primary, "s"); -MODULE_PARM_DESC(primary, "Primary network device to use"); -MODULE_PARM(multicast, "s"); -MODULE_PARM_DESC(multicast, "Mode for multicast support : 0 for none, 1 for active slave, 2 for all slaves (default)"); -MODULE_PARM(lacp_rate, "s"); -MODULE_PARM_DESC(lacp_rate, "LACPDU tx rate to request from 802.3ad partner (slow/fast)"); +static inline void bond_set_mode_ops(struct net_device *bond_dev, int mode); -static int bond_xmit_roundrobin(struct sk_buff *skb, struct net_device *dev); -static int bond_xmit_xor(struct sk_buff *skb, struct net_device *dev); -static int bond_xmit_activebackup(struct sk_buff *skb, struct net_device *dev); -static struct net_device_stats *bond_get_stats(struct net_device *dev); -static void bond_mii_monitor(struct net_device *dev); -static void loadbalance_arp_monitor(struct net_device *dev); -static void activebackup_arp_monitor(struct net_device *dev); -static void bond_mc_list_destroy(struct bonding *bond); -static void bond_mc_add(bonding_t *bond, void *addr, int alen); -static void bond_mc_delete(bonding_t *bond, void *addr, int alen); -static int bond_mc_list_copy (struct dev_mc_list *src, struct bonding *dst, int gpf_flag); -static inline int dmi_same(struct dev_mc_list *dmi1, struct dev_mc_list *dmi2); -static void bond_set_promiscuity(bonding_t *bond, int inc); -static void bond_set_allmulti(bonding_t *bond, int inc); -static struct dev_mc_list* bond_mc_list_find_dmi(struct dev_mc_list *dmi, struct dev_mc_list *mc_list); -static void bond_mc_update(bonding_t *bond, slave_t *new, slave_t *old); -static int bond_enslave(struct net_device *master, struct net_device *slave); -static int bond_release(struct net_device *master, struct net_device *slave); -static int bond_release_all(struct net_device *master); -static int bond_sethwaddr(struct net_device *master, struct net_device *slave); -static void change_active_interface(struct bonding *bond, struct slave *new); -static void reselect_active_interface(struct bonding *bond); -static struct slave *find_best_interface(struct bonding *bond); - - -/* #define BONDING_DEBUG 1 */ -#ifdef BONDING_DEBUG -#define dprintk(x...) printk(x...) -#else /* BONDING_DEBUG */ -#define dprintk(x...) do {} while (0) -#endif /* BONDING_DEBUG */ - -/* several macros */ - -static void arp_send_all(slave_t *slave) -{ - int i; - - for (i = 0; (idev, - my_ip, arp_target_hw_addr, slave->dev->dev_addr, - arp_target_hw_addr); - } -} - +/*---------------------------- General routines -----------------------------*/ -static const char * -bond_mode_name(void) +static const char *bond_mode_name(int mode) { - switch (bond_mode) { + switch (mode) { case BOND_MODE_ROUNDROBIN : return "load balancing (round-robin)"; case BOND_MODE_ACTIVEBACKUP : @@ -657,149 +620,7 @@ } } -static const char * -multicast_mode_name(void) -{ - switch(multicast_mode) { - case BOND_MULTICAST_DISABLED : - return "disabled"; - case BOND_MULTICAST_ACTIVE : - return "active slave only"; - case BOND_MULTICAST_ALL : - return "all slaves"; - default : - return "unknown"; - } -} - -void bond_set_slave_inactive_flags(slave_t *slave) -{ - slave->state = BOND_STATE_BACKUP; - slave->dev->flags |= IFF_NOARP; -} - -void bond_set_slave_active_flags(slave_t *slave) -{ - slave->state = BOND_STATE_ACTIVE; - slave->dev->flags &= ~IFF_NOARP; -} - -/* - * This function counts and verifies the the number of attached - * slaves, checking the count against the expected value (given that incr - * is either 1 or -1, for add or removal of a slave). Only - * bond_xmit_xor() uses the slave_cnt value, but this is still a good - * consistency check. - */ -static inline void -update_slave_cnt(bonding_t *bond, int incr) -{ - slave_t *slave = NULL; - int expect = bond->slave_cnt + incr; - - bond->slave_cnt = 0; - for (slave = bond->prev; slave != (slave_t*)bond; - slave = slave->prev) { - bond->slave_cnt++; - } - - if (expect != bond->slave_cnt) - BUG(); -} - -/* - * This function detaches the slave from the list . - * WARNING: no check is made to verify if the slave effectively - * belongs to . It returns in case it's needed. - * Nothing is freed on return, structures are just unchained. - * If the bond->current_slave pointer was pointing to , - * it should be changed by the calling function. - * - * bond->lock held for writing by caller. - */ -static slave_t * -bond_detach_slave(bonding_t *bond, slave_t *slave) -{ - if ((bond == NULL) || (slave == NULL) || - ((void *)bond == (void *)slave)) { - printk(KERN_ERR - "bond_detach_slave(): trying to detach " - "slave %p from bond %p\n", bond, slave); - return slave; - } - - if (bond->next == slave) { /* is the slave at the head ? */ - if (bond->prev == slave) { /* is the slave alone ? */ - bond->prev = bond->next = (slave_t *)bond; - } else { /* not alone */ - bond->next = slave->next; - slave->next->prev = (slave_t *)bond; - bond->prev->next = slave->next; - } - } else { - slave->prev->next = slave->next; - if (bond->prev == slave) { /* is this slave the last one ? */ - bond->prev = slave->prev; - } else { - slave->next->prev = slave->prev; - } - } - - update_slave_cnt(bond, -1); - - return slave; -} - -/* - * This function attaches the slave to the list . - * - * bond->lock held for writing by caller. - */ -static void -bond_attach_slave(struct bonding *bond, struct slave *new_slave) -{ - /* - * queue to the end of the slaves list, make the first element its - * successor, the last one its predecessor, and make it the bond's - * predecessor. - * - * Just to clarify, so future bonding driver hackers don't go through - * the same confusion stage I did trying to figure this out, the - * slaves are stored in a double linked circular list, sortof. - * In the ->next direction, the last slave points to the first slave, - * bypassing bond; only the slaves are in the ->next direction. - * In the ->prev direction, however, the first slave points to bond - * and bond points to the last slave. - * - * It looks like a circle with a little bubble hanging off one side - * in the ->prev direction only. - * - * When going through the list once, its best to start at bond->prev - * and go in the ->prev direction, testing for bond. Doing this - * in the ->next direction doesn't work. Trust me, I know this now. - * :) -mts 2002.03.14 - */ - new_slave->prev = bond->prev; - new_slave->prev->next = new_slave; - bond->prev = new_slave; - new_slave->next = bond->next; - - update_slave_cnt(bond, 1); -} - - -/* - * Less bad way to call ioctl from within the kernel; this needs to be - * done some other way to get the call out of interrupt context. - * Needs "ioctl" variable to be supplied by calling context. - */ -#define IOCTL(dev, arg, cmd) ({ \ - int ret; \ - mm_segment_t fs = get_fs(); \ - set_fs(get_ds()); \ - ret = ioctl(dev, arg, cmd); \ - set_fs(fs); \ - ret; }) +/*------------------------------- Link status -------------------------------*/ /* * Get link speed and duplex from the slave's base driver @@ -809,52 +630,63 @@ */ static int bond_update_speed_duplex(struct slave *slave) { - struct net_device *dev = slave->dev; + struct net_device *slave_dev = slave->dev; static int (* ioctl)(struct net_device *, struct ifreq *, int); struct ifreq ifr; struct ethtool_cmd etool; - ioctl = dev->do_ioctl; - if (ioctl) { - etool.cmd = ETHTOOL_GSET; - ifr.ifr_data = (char*)&etool; - if (IOCTL(dev, &ifr, SIOCETHTOOL) == 0) { - slave->speed = etool.speed; - slave->duplex = etool.duplex; - } else { - goto err_out; + /* Fake speed and duplex */ + slave->speed = SPEED_100; + slave->duplex = DUPLEX_FULL; + + if (slave_dev->ethtool_ops) { + u32 res; + + if (!slave_dev->ethtool_ops->get_settings) { + return -1; } - } else { - goto err_out; + + res = slave_dev->ethtool_ops->get_settings(slave_dev, &etool); + if (res < 0) { + return -1; + } + + goto verify; } - switch (slave->speed) { - case SPEED_10: - case SPEED_100: - case SPEED_1000: - break; - default: - goto err_out; + ioctl = slave_dev->do_ioctl; + strncpy(ifr.ifr_name, slave_dev->name, IFNAMSIZ); + etool.cmd = ETHTOOL_GSET; + ifr.ifr_data = (char*)&etool; + if (!ioctl || (IOCTL(slave_dev, &ifr, SIOCETHTOOL) < 0)) { + return -1; + } + +verify: + switch (etool.speed) { + case SPEED_10: + case SPEED_100: + case SPEED_1000: + break; + default: + return -1; } - switch (slave->duplex) { - case DUPLEX_FULL: - case DUPLEX_HALF: - break; - default: - goto err_out; + switch (etool.duplex) { + case DUPLEX_FULL: + case DUPLEX_HALF: + break; + default: + return -1; } - return 0; + slave->speed = etool.speed; + slave->duplex = etool.duplex; -err_out: - /* Fake speed and duplex */ - slave->speed = SPEED_100; - slave->duplex = DUPLEX_FULL; - return -1; + return 0; } -/* +/* * if supports MII link status reporting, check its link status. * * We either do MII/ETHTOOL ioctls, or check netif_carrier_ok(), @@ -870,19 +702,18 @@ * It'd be nice if there was a good way to tell if a driver supports * netif_carrier, but there really isn't. */ -static int -bond_check_dev_link(struct net_device *dev, int reporting) +static int bond_check_dev_link(struct bonding *bond, struct net_device *slave_dev, int reporting) { static int (* ioctl)(struct net_device *, struct ifreq *, int); struct ifreq ifr; struct mii_ioctl_data *mii; struct ethtool_value etool; - if (use_carrier) { - return netif_carrier_ok(dev) ? BMSR_LSTATUS : 0; + if (bond->params.use_carrier) { + return netif_carrier_ok(slave_dev) ? BMSR_LSTATUS : 0; } - ioctl = dev->do_ioctl; + ioctl = slave_dev->do_ioctl; if (ioctl) { /* TODO: set pointer to correct ioctl on a per team member */ /* bases to make this more efficient. that is, once */ @@ -897,477 +728,509 @@ */ /* Yes, the mii is overlaid on the ifreq.ifr_ifru */ + strncpy(ifr.ifr_name, slave_dev->name, IFNAMSIZ); mii = (struct mii_ioctl_data *)&ifr.ifr_data; - if (IOCTL(dev, &ifr, SIOCGMIIPHY) == 0) { + if (IOCTL(slave_dev, &ifr, SIOCGMIIPHY) == 0) { mii->reg_num = MII_BMSR; - if (IOCTL(dev, &ifr, SIOCGMIIREG) == 0) { - return mii->val_out & BMSR_LSTATUS; + if (IOCTL(slave_dev, &ifr, SIOCGMIIREG) == 0) { + return (mii->val_out & BMSR_LSTATUS); } } + } - /* try SIOCETHTOOL ioctl, some drivers cache ETHTOOL_GLINK */ - /* for a period of time so we attempt to get link status */ - /* from it last if the above MII ioctls fail... */ - etool.cmd = ETHTOOL_GLINK; - ifr.ifr_data = (char*)&etool; - if (IOCTL(dev, &ifr, SIOCETHTOOL) == 0) { + /* try SIOCETHTOOL ioctl, some drivers cache ETHTOOL_GLINK */ + /* for a period of time so we attempt to get link status */ + /* from it last if the above MII ioctls fail... */ + if (slave_dev->ethtool_ops) { + if (slave_dev->ethtool_ops->get_link) { + u32 link; + + link = slave_dev->ethtool_ops->get_link(slave_dev); + + return link ? BMSR_LSTATUS : 0; + } + } + + if (ioctl) { + strncpy(ifr.ifr_name, slave_dev->name, IFNAMSIZ); + etool.cmd = ETHTOOL_GLINK; + ifr.ifr_data = (char*)&etool; + if (IOCTL(slave_dev, &ifr, SIOCETHTOOL) == 0) { if (etool.data == 1) { return BMSR_LSTATUS; - } else { -#ifdef BONDING_DEBUG - printk(KERN_INFO - ":: SIOCETHTOOL shows link down \n"); -#endif + } else { + dprintk("SIOCETHTOOL shows link down\n"); return 0; - } + } } - } - + /* * If reporting, report that either there's no dev->do_ioctl, * or both SIOCGMIIREG and SIOCETHTOOL failed (meaning that we * cannot report link status). If not reporting, pretend * we're ok. */ - return reporting ? -1 : BMSR_LSTATUS; + return (reporting ? -1 : BMSR_LSTATUS); } -static u16 bond_check_mii_link(bonding_t *bond) -{ - int has_active_interface = 0; - - read_lock_bh(&bond->lock); - read_lock(&bond->ptrlock); - has_active_interface = (bond->current_slave != NULL); - read_unlock(&bond->ptrlock); - read_unlock_bh(&bond->lock); +/*----------------------------- Multicast list ------------------------------*/ - return (has_active_interface ? BMSR_LSTATUS : 0); +/* + * Returns 0 if dmi1 and dmi2 are the same, non-0 otherwise + */ +static inline int bond_is_dmi_same(struct dev_mc_list *dmi1, struct dev_mc_list *dmi2) +{ + return memcmp(dmi1->dmi_addr, dmi2->dmi_addr, dmi1->dmi_addrlen) == 0 && + dmi1->dmi_addrlen == dmi2->dmi_addrlen; } -/* register to receive lacpdus on a bond */ -static void bond_register_lacpdu(struct bonding *bond) +/* + * returns dmi entry if found, NULL otherwise + */ +static struct dev_mc_list *bond_mc_list_find_dmi(struct dev_mc_list *dmi, struct dev_mc_list *mc_list) { - struct packet_type* pk_type = &(BOND_AD_INFO(bond).ad_pkt_type); + struct dev_mc_list *idmi; - /* initialize packet type */ - pk_type->type = PKT_TYPE_LACPDU; - pk_type->dev = bond->device; - pk_type->func = bond_3ad_lacpdu_recv; + for (idmi = mc_list; idmi; idmi = idmi->next) { + if (bond_is_dmi_same(dmi, idmi)) { + return idmi; + } + } - dev_add_pack(pk_type); + return NULL; } -/* unregister to receive lacpdus on a bond */ -static void bond_unregister_lacpdu(struct bonding *bond) +/* + * Push the promiscuity flag down to appropriate slaves + */ +static void bond_set_promiscuity(struct bonding *bond, int inc) { - dev_remove_pack(&(BOND_AD_INFO(bond).ad_pkt_type)); + if (USES_PRIMARY(bond->params.mode)) { + /* write lock already acquired */ + if (bond->curr_active_slave) { + dev_set_promiscuity(bond->curr_active_slave->dev, inc); + } + } else { + struct slave *slave; + int i; + bond_for_each_slave(bond, slave, i) { + dev_set_promiscuity(slave->dev, inc); + } + } } -static int bond_open(struct net_device *dev) +/* + * Push the allmulti flag down to all slaves + */ +static void bond_set_allmulti(struct bonding *bond, int inc) { - struct bonding *bond = (struct bonding *)(dev->priv); - struct timer_list *timer = &((struct bonding *)(dev->priv))->mii_timer; - struct timer_list *arp_timer = &((struct bonding *)(dev->priv))->arp_timer; - - if ((bond_mode == BOND_MODE_TLB) || - (bond_mode == BOND_MODE_ALB)) { - struct timer_list *alb_timer = &(BOND_ALB_INFO(bond).alb_timer); - - /* bond_alb_initialize must be called before the timer - * is started. - */ - if (bond_alb_initialize(bond, (bond_mode == BOND_MODE_ALB))) { - /* something went wrong - fail the open operation */ - return -1; + if (USES_PRIMARY(bond->params.mode)) { + /* write lock already acquired */ + if (bond->curr_active_slave) { + dev_set_allmulti(bond->curr_active_slave->dev, inc); } - - init_timer(alb_timer); - alb_timer->expires = jiffies + 1; - alb_timer->data = (unsigned long)bond; - alb_timer->function = (void *)&bond_alb_monitor; - add_timer(alb_timer); - } - - if (miimon > 0) { /* link check interval, in milliseconds. */ - init_timer(timer); - timer->expires = jiffies + (miimon * HZ / 1000); - timer->data = (unsigned long)dev; - timer->function = (void *)&bond_mii_monitor; - add_timer(timer); - } - - if (arp_interval> 0) { /* arp interval, in milliseconds. */ - init_timer(arp_timer); - arp_timer->expires = jiffies + (arp_interval * HZ / 1000); - arp_timer->data = (unsigned long)dev; - if (bond_mode == BOND_MODE_ACTIVEBACKUP) { - arp_timer->function = (void *)&activebackup_arp_monitor; - } else { - arp_timer->function = (void *)&loadbalance_arp_monitor; + } else { + struct slave *slave; + int i; + bond_for_each_slave(bond, slave, i) { + dev_set_allmulti(slave->dev, inc); } - add_timer(arp_timer); } +} - if (bond_mode == BOND_MODE_8023AD) { - struct timer_list *ad_timer = &(BOND_AD_INFO(bond).ad_timer); - init_timer(ad_timer); - ad_timer->expires = jiffies + (AD_TIMER_INTERVAL * HZ / 1000); - ad_timer->data = (unsigned long)bond; - ad_timer->function = (void *)&bond_3ad_state_machine_handler; - add_timer(ad_timer); - - /* register to receive LACPDUs */ - bond_register_lacpdu(bond); +/* + * Add a Multicast address to slaves + * according to mode + */ +static void bond_mc_add(struct bonding *bond, void *addr, int alen) +{ + if (USES_PRIMARY(bond->params.mode)) { + /* write lock already acquired */ + if (bond->curr_active_slave) { + dev_mc_add(bond->curr_active_slave->dev, addr, alen, 0); + } + } else { + struct slave *slave; + int i; + bond_for_each_slave(bond, slave, i) { + dev_mc_add(slave->dev, addr, alen, 0); + } } - - return 0; } -static int bond_close(struct net_device *master) +/* + * Remove a multicast address from slave + * according to mode + */ +static void bond_mc_delete(struct bonding *bond, void *addr, int alen) { - bonding_t *bond = (struct bonding *) master->priv; - - write_lock_bh(&bond->lock); - - if (miimon > 0) { /* link check interval, in milliseconds. */ - del_timer(&bond->mii_timer); - } - if (arp_interval> 0) { /* arp interval, in milliseconds. */ - del_timer(&bond->arp_timer); - if (arp_target_hw_addr != NULL) { - kfree(arp_target_hw_addr); - arp_target_hw_addr = NULL; + if (USES_PRIMARY(bond->params.mode)) { + /* write lock already acquired */ + if (bond->curr_active_slave) { + dev_mc_delete(bond->curr_active_slave->dev, addr, alen, 0); + } + } else { + struct slave *slave; + int i; + bond_for_each_slave(bond, slave, i) { + dev_mc_delete(slave->dev, addr, alen, 0); } } +} - if (bond_mode == BOND_MODE_8023AD) { - del_timer_sync(&(BOND_AD_INFO(bond).ad_timer)); +/* + * Totally destroys the mc_list in bond + */ +static void bond_mc_list_destroy(struct bonding *bond) +{ + struct dev_mc_list *dmi; - /* Unregister the receive of LACPDUs */ - bond_unregister_lacpdu(bond); + dmi = bond->mc_list; + while (dmi) { + bond->mc_list = dmi->next; + kfree(dmi); + dmi = bond->mc_list; } +} - bond_mc_list_destroy (bond); - - write_unlock_bh(&bond->lock); +/* + * Copy all the Multicast addresses from src to the bonding device dst + */ +static int bond_mc_list_copy(struct dev_mc_list *mc_list, struct bonding *bond, int gpf_flag) +{ + struct dev_mc_list *dmi, *new_dmi; - /* Release the bonded slaves */ - bond_release_all(master); + for (dmi = mc_list; dmi; dmi = dmi->next) { + new_dmi = kmalloc(sizeof(struct dev_mc_list), gpf_flag); - if ((bond_mode == BOND_MODE_TLB) || - (bond_mode == BOND_MODE_ALB)) { - del_timer_sync(&(BOND_ALB_INFO(bond).alb_timer)); + if (!new_dmi) { + /* FIXME: Potential memory leak !!! */ + return -ENOMEM; + } - bond_alb_deinitialize(bond); + new_dmi->next = bond->mc_list; + bond->mc_list = new_dmi; + new_dmi->dmi_addrlen = dmi->dmi_addrlen; + memcpy(new_dmi->dmi_addr, dmi->dmi_addr, dmi->dmi_addrlen); + new_dmi->dmi_users = dmi->dmi_users; + new_dmi->dmi_gusers = dmi->dmi_gusers; } return 0; } -/* +/* * flush all members of flush->mc_list from device dev->mc_list */ -static void bond_mc_list_flush(struct net_device *dev, struct net_device *flush) -{ - struct dev_mc_list *dmi; - - for (dmi = flush->mc_list; dmi != NULL; dmi = dmi->next) - dev_mc_delete(dev, dmi->dmi_addr, dmi->dmi_addrlen, 0); +static void bond_mc_list_flush(struct net_device *bond_dev, struct net_device *slave_dev) +{ + struct bonding *bond = bond_dev->priv; + struct dev_mc_list *dmi; - if (bond_mode == BOND_MODE_8023AD) { + for (dmi = bond_dev->mc_list; dmi; dmi = dmi->next) { + dev_mc_delete(slave_dev, dmi->dmi_addr, dmi->dmi_addrlen, 0); + } + + if (bond->params.mode == BOND_MODE_8023AD) { /* del lacpdu mc addr from mc list */ u8 lacpdu_multicast[ETH_ALEN] = MULTICAST_LACPDU_ADDR; - dev_mc_delete(dev, lacpdu_multicast, ETH_ALEN, 0); + dev_mc_delete(slave_dev, lacpdu_multicast, ETH_ALEN, 0); } } +/*--------------------------- Active slave change ---------------------------*/ + /* - * Totally destroys the mc_list in bond + * Update the mc list and multicast-related flags for the new and + * old active slaves (if any) according to the multicast mode, and + * promiscuous flags unconditionally. */ -static void bond_mc_list_destroy(struct bonding *bond) +static void bond_mc_swap(struct bonding *bond, struct slave *new_active, struct slave *old_active) { struct dev_mc_list *dmi; - dmi = bond->mc_list; - while (dmi) { - bond->mc_list = dmi->next; - kfree(dmi); - dmi = bond->mc_list; - } -} - -/* - * Add a Multicast address to every slave in the bonding group - */ -static void bond_mc_add(bonding_t *bond, void *addr, int alen) -{ - slave_t *slave; - switch (multicast_mode) { - case BOND_MULTICAST_ACTIVE : - /* write lock already acquired */ - if (bond->current_slave != NULL) - dev_mc_add(bond->current_slave->dev, addr, alen, 0); - break; - case BOND_MULTICAST_ALL : - for (slave = bond->prev; slave != (slave_t*)bond; slave = slave->prev) - dev_mc_add(slave->dev, addr, alen, 0); - break; - case BOND_MULTICAST_DISABLED : - break; + if (!USES_PRIMARY(bond->params.mode)) { + /* nothing to do - mc list is already up-to-date on + * all slaves + */ + return; } -} -/* - * Remove a multicast address from every slave in the bonding group - */ -static void bond_mc_delete(bonding_t *bond, void *addr, int alen) -{ - slave_t *slave; - switch (multicast_mode) { - case BOND_MULTICAST_ACTIVE : - /* write lock already acquired */ - if (bond->current_slave != NULL) - dev_mc_delete(bond->current_slave->dev, addr, alen, 0); - break; - case BOND_MULTICAST_ALL : - for (slave = bond->prev; slave != (slave_t*)bond; slave = slave->prev) - dev_mc_delete(slave->dev, addr, alen, 0); - break; - case BOND_MULTICAST_DISABLED : - break; - } -} + if (old_active) { + if (bond->dev->flags & IFF_PROMISC) { + dev_set_promiscuity(old_active->dev, -1); + } -/* - * Copy all the Multicast addresses from src to the bonding device dst - */ -static int bond_mc_list_copy (struct dev_mc_list *src, struct bonding *dst, - int gpf_flag) -{ - struct dev_mc_list *dmi, *new_dmi; + if (bond->dev->flags & IFF_ALLMULTI) { + dev_set_allmulti(old_active->dev, -1); + } - for (dmi = src; dmi != NULL; dmi = dmi->next) { - new_dmi = kmalloc(sizeof(struct dev_mc_list), gpf_flag); + for (dmi = bond->dev->mc_list; dmi; dmi = dmi->next) { + dev_mc_delete(old_active->dev, dmi->dmi_addr, dmi->dmi_addrlen, 0); + } + } - if (new_dmi == NULL) { - return -ENOMEM; + if (new_active) { + if (bond->dev->flags & IFF_PROMISC) { + dev_set_promiscuity(new_active->dev, 1); } - new_dmi->next = dst->mc_list; - dst->mc_list = new_dmi; + if (bond->dev->flags & IFF_ALLMULTI) { + dev_set_allmulti(new_active->dev, 1); + } - new_dmi->dmi_addrlen = dmi->dmi_addrlen; - memcpy(new_dmi->dmi_addr, dmi->dmi_addr, dmi->dmi_addrlen); - new_dmi->dmi_users = dmi->dmi_users; - new_dmi->dmi_gusers = dmi->dmi_gusers; - } - return 0; + for (dmi = bond->dev->mc_list; dmi; dmi = dmi->next) { + dev_mc_add(new_active->dev, dmi->dmi_addr, dmi->dmi_addrlen, 0); + } + } } -/* - * Returns 0 if dmi1 and dmi2 are the same, non-0 otherwise +/** + * find_best_interface - select the best available slave to be the active one + * @bond: our bonding struct + * + * Warning: Caller must hold curr_slave_lock for writing. */ -static inline int dmi_same(struct dev_mc_list *dmi1, struct dev_mc_list *dmi2) -{ - return memcmp(dmi1->dmi_addr, dmi2->dmi_addr, dmi1->dmi_addrlen) == 0 && - dmi1->dmi_addrlen == dmi2->dmi_addrlen; -} +static struct slave *bond_find_best_slave(struct bonding *bond) +{ + struct slave *new_active, *old_active; + struct slave *bestslave = NULL; + int mintime = bond->params.updelay; + int i; -/* - * Push the promiscuity flag down to appropriate slaves - */ -static void bond_set_promiscuity(bonding_t *bond, int inc) -{ - slave_t *slave; - - if (USES_PRIMARY(bond_mode)) { - if (bond->current_slave) { - dev_set_promiscuity(bond->current_slave->dev, inc); - } + new_active = old_active = bond->curr_active_slave; - } else { - for (slave = bond->prev; slave != (slave_t*)bond; - slave = slave->prev) { - dev_set_promiscuity(slave->dev, inc); + if (!new_active) { /* there were no active slaves left */ + if (bond->slave_cnt > 0) { /* found one slave */ + new_active = bond->first_slave; + } else { + return NULL; /* still no slave, return NULL */ } } -} -/* - * Push the allmulti flag down to all slaves - */ -static void bond_set_allmulti(bonding_t *bond, int inc) -{ - slave_t *slave; - switch (multicast_mode) { - case BOND_MULTICAST_ACTIVE : - /* write lock already acquired */ - if (bond->current_slave != NULL) - dev_set_allmulti(bond->current_slave->dev, inc); - break; - case BOND_MULTICAST_ALL : - for (slave = bond->prev; slave != (slave_t*)bond; slave = slave->prev) - dev_set_allmulti(slave->dev, inc); - break; - case BOND_MULTICAST_DISABLED : - break; + /* first try the primary link; if arping, a link must tx/rx traffic + * before it can be considered the curr_active_slave - also, we would skip + * slaves between the curr_active_slave and primary_slave that may be up + * and able to arp + */ + if ((bond->primary_slave) && + (!bond->params.arp_interval) && + (IS_UP(bond->primary_slave->dev))) { + new_active = bond->primary_slave; } -} -/* - * returns dmi entry if found, NULL otherwise - */ -static struct dev_mc_list* bond_mc_list_find_dmi(struct dev_mc_list *dmi, - struct dev_mc_list *mc_list) -{ - struct dev_mc_list *idmi; + /* remember where to stop iterating over the slaves */ + old_active = new_active; - for (idmi = mc_list; idmi != NULL; idmi = idmi->next) { - if (dmi_same(dmi, idmi)) { - return idmi; + bond_for_each_slave_from(bond, new_active, i, old_active) { + if (IS_UP(new_active->dev)) { + if (new_active->link == BOND_LINK_UP) { + return new_active; + } else if (new_active->link == BOND_LINK_BACK) { + /* link up, but waiting for stabilization */ + if (new_active->delay < mintime) { + mintime = new_active->delay; + bestslave = new_active; + } + } } } - return NULL; -} -static void set_multicast_list(struct net_device *master) + return bestslave; +} + +/** + * change_active_interface - change the active slave into the specified one + * @bond: our bonding struct + * @new: the new slave to make the active one + * + * Set the new slave to the bond's settings and unset them on the old + * curr_active_slave. + * Setting include flags, mc-list, promiscuity, allmulti, etc. + * + * If @new's link state is %BOND_LINK_BACK we'll set it to %BOND_LINK_UP, + * because it is apparently the best available slave we have, even though its + * updelay hasn't timed out yet. + * + * Warning: Caller must hold curr_slave_lock for writing. + */ +static void bond_change_active_slave(struct bonding *bond, struct slave *new_active) { - bonding_t *bond = master->priv; - struct dev_mc_list *dmi; + struct slave *old_active = bond->curr_active_slave; - write_lock_bh(&bond->lock); + if (old_active == new_active) { + return; + } - /* - * Do promisc before checking multicast_mode - */ - if ( (master->flags & IFF_PROMISC) && !(bond->flags & IFF_PROMISC) ) - bond_set_promiscuity(bond, 1); + if (new_active) { + if (new_active->link == BOND_LINK_BACK) { + if (USES_PRIMARY(bond->params.mode)) { + printk(KERN_INFO DRV_NAME + ": %s: making interface %s the new " + "active one %d ms earlier.\n", + bond->dev->name, new_active->dev->name, + (bond->params.updelay - new_active->delay) * bond->params.miimon); + } - if ( !(master->flags & IFF_PROMISC) && (bond->flags & IFF_PROMISC) ) - bond_set_promiscuity(bond, -1); + new_active->delay = 0; + new_active->link = BOND_LINK_UP; + new_active->jiffies = jiffies; - if (multicast_mode == BOND_MULTICAST_DISABLED) { - bond->flags = master->flags; - write_unlock_bh(&bond->lock); - return; + if (bond->params.mode == BOND_MODE_8023AD) { + bond_3ad_handle_link_change(new_active, BOND_LINK_UP); + } + + if ((bond->params.mode == BOND_MODE_TLB) || + (bond->params.mode == BOND_MODE_ALB)) { + bond_alb_handle_link_change(bond, new_active, BOND_LINK_UP); + } + } else { + if (USES_PRIMARY(bond->params.mode)) { + printk(KERN_INFO DRV_NAME + ": %s: making interface %s the new " + "active one.\n", + bond->dev->name, new_active->dev->name); + } + } } - /* set allmulti flag to slaves */ - if ( (master->flags & IFF_ALLMULTI) && !(bond->flags & IFF_ALLMULTI) ) - bond_set_allmulti(bond, 1); + if (bond->params.mode == BOND_MODE_ACTIVEBACKUP) { + if (old_active) { + bond_set_slave_inactive_flags(old_active); + } - if ( !(master->flags & IFF_ALLMULTI) && (bond->flags & IFF_ALLMULTI) ) - bond_set_allmulti(bond, -1); + if (new_active) { + bond_set_slave_active_flags(new_active); + } + } - bond->flags = master->flags; + if (USES_PRIMARY(bond->params.mode)) { + bond_mc_swap(bond, new_active, old_active); + } + + if ((bond->params.mode == BOND_MODE_TLB) || + (bond->params.mode == BOND_MODE_ALB)) { + bond_alb_handle_active_change(bond, new_active); + } else { + bond->curr_active_slave = new_active; + } +} - /* looking for addresses to add to slaves' mc list */ - for (dmi = master->mc_list; dmi != NULL; dmi = dmi->next) { - if (bond_mc_list_find_dmi(dmi, bond->mc_list) == NULL) - bond_mc_add(bond, dmi->dmi_addr, dmi->dmi_addrlen); - } +/** + * bond_select_active_slave - select a new active slave, if needed + * @bond: our bonding struct + * + * This functions shoud be called when one of the following occurs: + * - The old curr_active_slave has been released or lost its link. + * - The primary_slave has got its link back. + * - A slave has got its link back and there's no old curr_active_slave. + * + * Warning: Caller must hold curr_slave_lock for writing. + */ +static void bond_select_active_slave(struct bonding *bond) +{ + struct slave *best_slave; - /* looking for addresses to delete from slaves' list */ - for (dmi = bond->mc_list; dmi != NULL; dmi = dmi->next) { - if (bond_mc_list_find_dmi(dmi, master->mc_list) == NULL) - bond_mc_delete(bond, dmi->dmi_addr, dmi->dmi_addrlen); + best_slave = bond_find_best_slave(bond); + if (best_slave != bond->curr_active_slave) { + bond_change_active_slave(bond, best_slave); } +} +/*--------------------------- slave list handling ---------------------------*/ - /* save master's multicast list */ - bond_mc_list_destroy (bond); - bond_mc_list_copy (master->mc_list, bond, GFP_ATOMIC); +/* + * This function attaches the slave to the end of list. + * + * bond->lock held for writing by caller. + */ +static void bond_attach_slave(struct bonding *bond, struct slave *new_slave) +{ + if (bond->first_slave == NULL) { /* attaching the first slave */ + new_slave->next = new_slave; + new_slave->prev = new_slave; + bond->first_slave = new_slave; + } else { + new_slave->next = bond->first_slave; + new_slave->prev = bond->first_slave->prev; + new_slave->next->prev = new_slave; + new_slave->prev->next = new_slave; + } - write_unlock_bh(&bond->lock); + bond->slave_cnt++; } /* - * Update the mc list and multicast-related flags for the new and - * old active slaves (if any) according to the multicast mode, and - * promiscuous flags unconditionally. + * This function detaches the slave from the list. + * WARNING: no check is made to verify if the slave effectively + * belongs to . + * Nothing is freed on return, structures are just unchained. + * If any slave pointer in bond was pointing to , + * it should be changed by the calling function. + * + * bond->lock held for writing by caller. */ -static void bond_mc_update(bonding_t *bond, slave_t *new, slave_t *old) +static void bond_detach_slave(struct bonding *bond, struct slave *slave) { - struct dev_mc_list *dmi; + if (slave->next) { + slave->next->prev = slave->prev; + } - if (USES_PRIMARY(bond_mode)) { - if (bond->device->flags & IFF_PROMISC) { - if (old) - dev_set_promiscuity(old->dev, -1); - if (new) - dev_set_promiscuity(new->dev, 1); - } + if (slave->prev) { + slave->prev->next = slave->next; } - switch(multicast_mode) { - case BOND_MULTICAST_ACTIVE : - if (bond->device->flags & IFF_ALLMULTI) { - if (old) - dev_set_allmulti(old->dev, -1); - if (new) - dev_set_allmulti(new->dev, 1); - } - /* first remove all mc addresses from old slave if any, - and _then_ add them to new active slave */ - if (old) { - for (dmi = bond->device->mc_list; dmi != NULL; dmi = dmi->next) - dev_mc_delete(old->dev, dmi->dmi_addr, dmi->dmi_addrlen, 0); - } - if (new) { - for (dmi = bond->device->mc_list; dmi != NULL; dmi = dmi->next) - dev_mc_add(new->dev, dmi->dmi_addr, dmi->dmi_addrlen, 0); + if (bond->first_slave == slave) { /* slave is the first slave */ + if (bond->slave_cnt > 1) { /* there are more slave */ + bond->first_slave = slave->next; + } else { + bond->first_slave = NULL; /* slave was the last one */ } - break; - case BOND_MULTICAST_ALL : - /* nothing to do: mc list is already up-to-date on all slaves */ - break; - case BOND_MULTICAST_DISABLED : - break; } + + slave->next = NULL; + slave->prev = NULL; + bond->slave_cnt--; +} + +/*---------------------------------- IOCTL ----------------------------------*/ + +static int bond_sethwaddr(struct net_device *bond_dev, struct net_device *slave_dev) +{ + dprintk("bond_dev=%p\n", bond_dev); + dprintk("slave_dev=%p\n", slave_dev); + dprintk("slave_dev->addr_len=%d\n", slave_dev->addr_len); + memcpy(bond_dev->dev_addr, slave_dev->dev_addr, slave_dev->addr_len); + return 0; } /* enslave device to bond device */ -static int bond_enslave(struct net_device *master_dev, - struct net_device *slave_dev) +static int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) { - bonding_t *bond = NULL; - slave_t *new_slave = NULL; - unsigned long rflags = 0; - int err = 0; + struct bonding *bond = bond_dev->priv; + struct slave *new_slave = NULL; struct dev_mc_list *dmi; - struct in_ifaddr **ifap; - struct in_ifaddr *ifa; - int link_reporting; struct sockaddr addr; - - if (master_dev == NULL || slave_dev == NULL) { - return -ENODEV; - } - bond = (struct bonding *) master_dev->priv; + int link_reporting; + int res = 0; if (slave_dev->do_ioctl == NULL) { - printk(KERN_DEBUG - "Warning : no link monitoring support for %s\n", - slave_dev->name); + printk(KERN_WARNING DRV_NAME + ": Warning : no link monitoring support for %s\n", + slave_dev->name); } - /* bond must be initialized by bond_open() before enslaving */ - if (!(master_dev->flags & IFF_UP)) { -#ifdef BONDING_DEBUG - printk(KERN_CRIT "Error, master_dev is not up\n"); -#endif + if (!(bond_dev->flags & IFF_UP)) { + dprintk("Error, master_dev is not up\n"); return -EPERM; } /* already enslaved */ - if (master_dev->flags & IFF_SLAVE || slave_dev->flags & IFF_SLAVE) { -#ifdef BONDING_DEBUG - printk(KERN_CRIT "Error, Device was already enslaved\n"); -#endif + if (slave_dev->flags & IFF_SLAVE) { + dprintk("Error, Device was already enslaved\n"); return -EBUSY; } @@ -1376,19 +1239,19 @@ * slave interface to be closed. */ if ((slave_dev->flags & IFF_UP)) { -#ifdef BONDING_DEBUG - printk(KERN_CRIT "Error, slave_dev is up\n"); -#endif + printk(KERN_ERR DRV_NAME + ": Error: %s is up\n", + slave_dev->name); return -EPERM; } if (slave_dev->set_mac_address == NULL) { - printk(KERN_CRIT - "The slave device you specified does not support" - " setting the MAC address.\n"); - printk(KERN_CRIT - "Your kernel likely does not support slave" - " devices.\n"); + printk(KERN_ERR DRV_NAME + ": Error: The slave device you specified does " + "not support setting the MAC address.\n"); + printk(KERN_ERR + "Your kernel likely does not support slave " + "devices.\n"); return -EOPNOTSUPP; } @@ -1397,26 +1260,29 @@ * slave interface to be open. */ if (!(slave_dev->flags & IFF_UP)) { -#ifdef BONDING_DEBUG - printk(KERN_CRIT "Error, slave_dev is not running\n"); -#endif + printk(KERN_ERR DRV_NAME + ": Error: %s is not running\n", + slave_dev->name); return -EINVAL; } - if ((bond_mode == BOND_MODE_8023AD) || - (bond_mode == BOND_MODE_TLB) || - (bond_mode == BOND_MODE_ALB)) { - printk(KERN_ERR - "bonding: Error: to use %s mode, you must " - "upgrade ifenslave.\n", bond_mode_name()); + if ((bond->params.mode == BOND_MODE_8023AD) || + (bond->params.mode == BOND_MODE_TLB) || + (bond->params.mode == BOND_MODE_ALB)) { + printk(KERN_ERR DRV_NAME + ": Error: to use %s mode, you must upgrade " + "ifenslave.\n", + bond_mode_name(bond->params.mode)); return -EOPNOTSUPP; } } - if ((new_slave = kmalloc(sizeof(slave_t), GFP_KERNEL)) == NULL) { + new_slave = kmalloc(sizeof(struct slave), GFP_KERNEL); + if (!new_slave) { return -ENOMEM; } - memset(new_slave, 0, sizeof(slave_t)); + + memset(new_slave, 0, sizeof(struct slave)); /* save slave's original flags before calling * netdev_set_master and dev_open @@ -1430,37 +1296,29 @@ */ memcpy(new_slave->perm_hwaddr, slave_dev->dev_addr, ETH_ALEN); - if (bond->slave_cnt > 0) { - /* set slave to master's mac address - * The application already set the master's - * mac address to that of the first slave - */ - memcpy(addr.sa_data, master_dev->dev_addr, master_dev->addr_len); - addr.sa_family = slave_dev->type; - err = slave_dev->set_mac_address(slave_dev, &addr); - if (err) { -#ifdef BONDING_DEBUG - printk(KERN_CRIT "Error %d calling set_mac_address\n", err); -#endif - goto err_free; - } + /* set slave to master's mac address + * The application already set the master's + * mac address to that of the first slave + */ + memcpy(addr.sa_data, bond_dev->dev_addr, bond_dev->addr_len); + addr.sa_family = slave_dev->type; + res = slave_dev->set_mac_address(slave_dev, &addr); + if (res) { + dprintk("Error %d calling set_mac_address\n", res); + goto err_free; } /* open the slave since the application closed it */ - err = dev_open(slave_dev); - if (err) { -#ifdef BONDING_DEBUG - printk(KERN_CRIT "Openning slave %s failed\n", slave_dev->name); -#endif + res = dev_open(slave_dev); + if (res) { + dprintk("Openning slave %s failed\n", slave_dev->name); goto err_restore_mac; } } - err = netdev_set_master(slave_dev, master_dev); - if (err) { -#ifdef BONDING_DEBUG - printk(KERN_CRIT "Error %d calling netdev_set_master\n", err); -#endif + res = netdev_set_master(slave_dev, bond_dev); + if (res) { + dprintk("Error %d calling netdev_set_master\n", res); if (app_abi_ver < 1) { goto err_free; } else { @@ -1470,40 +1328,40 @@ new_slave->dev = slave_dev; - if ((bond_mode == BOND_MODE_TLB) || - (bond_mode == BOND_MODE_ALB)) { + if ((bond->params.mode == BOND_MODE_TLB) || + (bond->params.mode == BOND_MODE_ALB)) { /* bond_alb_init_slave() must be called before all other stages since * it might fail and we do not want to have to undo everything */ - err = bond_alb_init_slave(bond, new_slave); - if (err) { + res = bond_alb_init_slave(bond, new_slave); + if (res) { goto err_unset_master; } } - /* set promiscuity level to new slave */ - if (master_dev->flags & IFF_PROMISC) { - /* If the mode USES_PRIMARY, then the new slave gets the - * master's promisc (and mc) settings only if it becomes the - * current_slave, and that is taken care of later when calling - * bond_change_active() - */ - if (!USES_PRIMARY(bond_mode)) { - dev_set_promiscuity(slave_dev, 1); + /* If the mode USES_PRIMARY, then the new slave gets the + * master's promisc (and mc) settings only if it becomes the + * curr_active_slave, and that is taken care of later when calling + * bond_change_active() + */ + if (!USES_PRIMARY(bond->params.mode)) { + /* set promiscuity level to new slave */ + if (bond_dev->flags & IFF_PROMISC) { + dev_set_promiscuity(slave_dev, 1); } - } - - if (multicast_mode == BOND_MULTICAST_ALL) { + /* set allmulti level to new slave */ - if (master_dev->flags & IFF_ALLMULTI) - dev_set_allmulti(slave_dev, 1); - - /* upload master's mc_list to new slave */ - for (dmi = master_dev->mc_list; dmi != NULL; dmi = dmi->next) + if (bond_dev->flags & IFF_ALLMULTI) { + dev_set_allmulti(slave_dev, 1); + } + + /* upload master's mc_list to new slave */ + for (dmi = bond_dev->mc_list; dmi; dmi = dmi->next) { dev_mc_add (slave_dev, dmi->dmi_addr, dmi->dmi_addrlen, 0); + } } - if (bond_mode == BOND_MODE_8023AD) { + if (bond->params.mode == BOND_MODE_8023AD) { /* add lacpdu mc addr to mc list */ u8 lacpdu_multicast[ETH_ALEN] = MULTICAST_LACPDU_ADDR; @@ -1511,15 +1369,16 @@ } write_lock_bh(&bond->lock); - + bond_attach_slave(bond, new_slave); + new_slave->delay = 0; new_slave->link_failure_count = 0; - if (miimon > 0 && !use_carrier) { - link_reporting = bond_check_dev_link(slave_dev, 1); + if (bond->params.miimon && !bond->params.use_carrier) { + link_reporting = bond_check_dev_link(bond, slave_dev, 1); - if ((link_reporting == -1) && (arp_interval == 0)) { + if ((link_reporting == -1) && !bond->params.arp_interval) { /* * miimon is set but a bonded network driver * does not support ETHTOOL/MII and @@ -1528,157 +1387,136 @@ * here (because netif_carrier is always * supported); thus, we don't need to change * the messages for netif_carrier. - */ - printk(KERN_ERR - "bond_enslave(): MII and ETHTOOL support not " - "available for interface %s, and " - "arp_interval/arp_ip_target module parameters " - "not specified, thus bonding will not detect " - "link failures! see bonding.txt for details.\n", - slave_dev->name); + */ + printk(KERN_WARNING DRV_NAME + ": Warning: MII and ETHTOOL support not " + "available for interface %s, and " + "arp_interval/arp_ip_target module parameters " + "not specified, thus bonding will not detect " + "link failures! see bonding.txt for details.\n", + slave_dev->name); } else if (link_reporting == -1) { - /* unable get link status using mii/ethtool */ - printk(KERN_WARNING - "bond_enslave: can't get link status from " + /* unable get link status using mii/ethtool */ + printk(KERN_WARNING DRV_NAME + ": Warning: can't get link status from " "interface %s; the network driver associated " - "with this interface does not support " - "MII or ETHTOOL link status reporting, thus " - "miimon has no effect on this interface.\n", + "with this interface does not support MII or " + "ETHTOOL link status reporting, thus miimon " + "has no effect on this interface.\n", slave_dev->name); } } /* check for initial state */ - if ((miimon <= 0) || - (bond_check_dev_link(slave_dev, 0) == BMSR_LSTATUS)) { - if (updelay) { -#ifdef BONDING_DEBUG - printk(KERN_CRIT "Initial state of slave_dev is " - "BOND_LINK_BACK\n"); -#endif + if (!bond->params.miimon || + (bond_check_dev_link(bond, slave_dev, 0) == BMSR_LSTATUS)) { + if (bond->params.updelay) { + dprintk("Initial state of slave_dev is " + "BOND_LINK_BACK\n"); new_slave->link = BOND_LINK_BACK; - new_slave->delay = updelay; - } - else { -#ifdef BONDING_DEBUG - printk(KERN_DEBUG "Initial state of slave_dev is " + new_slave->delay = bond->params.updelay; + } else { + dprintk("Initial state of slave_dev is " "BOND_LINK_UP\n"); -#endif new_slave->link = BOND_LINK_UP; } new_slave->jiffies = jiffies; - } - else { -#ifdef BONDING_DEBUG - printk(KERN_CRIT "Initial state of slave_dev is " + } else { + dprintk("Initial state of slave_dev is " "BOND_LINK_DOWN\n"); -#endif new_slave->link = BOND_LINK_DOWN; } if (bond_update_speed_duplex(new_slave) && (new_slave->link != BOND_LINK_DOWN)) { - - printk(KERN_WARNING - "bond_enslave(): failed to get speed/duplex from %s, " - "speed forced to 100Mbps, duplex forced to Full.\n", + printk(KERN_WARNING DRV_NAME + ": Warning: failed to get speed/duplex from %s, speed " + "forced to 100Mbps, duplex forced to Full.\n", new_slave->dev->name); - if (bond_mode == BOND_MODE_8023AD) { + + if (bond->params.mode == BOND_MODE_8023AD) { printk(KERN_WARNING - "Operation of 802.3ad mode requires ETHTOOL support " - "in base driver for proper aggregator selection.\n"); + "Operation of 802.3ad mode requires ETHTOOL " + "support in base driver for proper aggregator " + "selection.\n"); } } - /* if we're in active-backup mode, we need one and only one active - * interface. The backup interfaces will have their NOARP flag set - * because we need them to be completely deaf and not to respond to - * any ARP request on the network to avoid fooling a switch. Thus, - * since we guarantee that current_slave always point to the last - * usable interface, we just have to verify this interface's flag. - */ - if (bond_mode == BOND_MODE_ACTIVEBACKUP) { - if (((bond->current_slave == NULL) - || (bond->current_slave->dev->flags & IFF_NOARP)) - && (new_slave->link != BOND_LINK_DOWN)) { -#ifdef BONDING_DEBUG - printk(KERN_CRIT "This is the first active slave\n"); -#endif + if (USES_PRIMARY(bond->params.mode) && bond->params.primary[0]) { + /* if there is a primary slave, remember it */ + if (strcmp(bond->params.primary, new_slave->dev->name) == 0) { + bond->primary_slave = new_slave; + } + } + + switch (bond->params.mode) { + case BOND_MODE_ACTIVEBACKUP: + /* if we're in active-backup mode, we need one and only one active + * interface. The backup interfaces will have their NOARP flag set + * because we need them to be completely deaf and not to respond to + * any ARP request on the network to avoid fooling a switch. Thus, + * since we guarantee that curr_active_slave always point to the last + * usable interface, we just have to verify this interface's flag. + */ + if (((!bond->curr_active_slave) || + (bond->curr_active_slave->dev->flags & IFF_NOARP)) && + (new_slave->link != BOND_LINK_DOWN)) { + dprintk("This is the first active slave\n"); /* first slave or no active slave yet, and this link is OK, so make this interface the active one */ - change_active_interface(bond, new_slave); - } - else { -#ifdef BONDING_DEBUG - printk(KERN_CRIT "This is just a backup slave\n"); -#endif + bond_change_active_slave(bond, new_slave); + } else { + dprintk("This is just a backup slave\n"); bond_set_slave_inactive_flags(new_slave); } - if (((struct in_device *)slave_dev->ip_ptr) != NULL) { - read_lock_irqsave(&(((struct in_device *)slave_dev->ip_ptr)->lock), rflags); - ifap= &(((struct in_device *)slave_dev->ip_ptr)->ifa_list); - ifa = *ifap; - if (ifa != NULL) - my_ip = ifa->ifa_address; - read_unlock_irqrestore(&(((struct in_device *)slave_dev->ip_ptr)->lock), rflags); - } - - /* if there is a primary slave, remember it */ - if (primary != NULL) { - if (strcmp(primary, new_slave->dev->name) == 0) { - bond->primary_slave = new_slave; - } - } - } else if (bond_mode == BOND_MODE_8023AD) { + break; + case BOND_MODE_8023AD: /* in 802.3ad mode, the internal mechanism * will activate the slaves in the selected * aggregator */ bond_set_slave_inactive_flags(new_slave); /* if this is the first slave */ - if (new_slave == bond->next) { + if (bond->slave_cnt == 1) { SLAVE_AD_INFO(new_slave).id = 1; /* Initialize AD with the number of times that the AD timer is called in 1 second * can be called only after the mac address of the bond is set */ bond_3ad_initialize(bond, 1000/AD_TIMER_INTERVAL, - lacp_fast); + bond->params.lacp_fast); } else { SLAVE_AD_INFO(new_slave).id = - SLAVE_AD_INFO(new_slave->prev).id + 1; + SLAVE_AD_INFO(new_slave->prev).id + 1; } bond_3ad_bind_slave(new_slave); - } else if ((bond_mode == BOND_MODE_TLB) || - (bond_mode == BOND_MODE_ALB)) { + break; + case BOND_MODE_TLB: + case BOND_MODE_ALB: new_slave->state = BOND_STATE_ACTIVE; - if ((bond->current_slave == NULL) && (new_slave->link != BOND_LINK_DOWN)) { + if ((!bond->curr_active_slave) && + (new_slave->link != BOND_LINK_DOWN)) { /* first slave or no active slave yet, and this link * is OK, so make this interface the active one */ - change_active_interface(bond, new_slave); + bond_change_active_slave(bond, new_slave); } + break; + default: + dprintk("This slave is always active in trunk mode\n"); - /* if there is a primary slave, remember it */ - if (primary != NULL) { - if (strcmp(primary, new_slave->dev->name) == 0) { - bond->primary_slave = new_slave; - } - } - } else { -#ifdef BONDING_DEBUG - printk(KERN_CRIT "This slave is always active in trunk mode\n"); -#endif /* always active in trunk mode */ new_slave->state = BOND_STATE_ACTIVE; - /* In trunking mode there is little meaning to current_slave + /* In trunking mode there is little meaning to curr_active_slave * anyway (it holds no special properties of the bond device), * so we can change it without calling change_active_interface() */ - if (bond->current_slave == NULL) - bond->current_slave = new_slave; - } + if (!bond->curr_active_slave) { + bond->curr_active_slave = new_slave; + } + break; + } /* switch(bond_mode) */ write_unlock_bh(&bond->lock); @@ -1692,38 +1530,34 @@ */ int ndx = 0; - for (ndx = 0; ndx < slave_dev->addr_len; ndx++) { -#ifdef BONDING_DEBUG - printk(KERN_DEBUG - "Checking ndx=%d of master_dev->dev_addr\n", ndx); -#endif - if (master_dev->dev_addr[ndx] != 0) { -#ifdef BONDING_DEBUG - printk(KERN_DEBUG - "Found non-zero byte at ndx=%d\n", ndx); -#endif + for (ndx = 0; ndx < bond_dev->addr_len; ndx++) { + dprintk("Checking ndx=%d of bond_dev->dev_addr\n", + ndx); + if (bond_dev->dev_addr[ndx] != 0) { + dprintk("Found non-zero byte at ndx=%d\n", + ndx); break; } } - if (ndx == slave_dev->addr_len) { + + if (ndx == bond_dev->addr_len) { /* * We got all the way through the address and it was * all 0's. */ -#ifdef BONDING_DEBUG - printk(KERN_DEBUG "%s doesn't have a MAC address yet. ", - master_dev->name); - printk(KERN_DEBUG "Going to give assign it from %s.\n", - slave_dev->name); -#endif - bond_sethwaddr(master_dev, slave_dev); + dprintk("%s doesn't have a MAC address yet. \n", + bond_dev->name); + dprintk("Going to give assign it from %s.\n", + slave_dev->name); + bond_sethwaddr(bond_dev, slave_dev); } } - printk (KERN_INFO "%s: enslaving %s as a%s interface with a%s link.\n", - master_dev->name, slave_dev->name, - new_slave->state == BOND_STATE_ACTIVE ? "n active" : " backup", - new_slave->link != BOND_LINK_DOWN ? "n up" : " down"); + printk(KERN_INFO DRV_NAME + ": %s: enslaving %s as a%s interface with a%s link.\n", + bond_dev->name, slave_dev->name, + new_slave->state == BOND_STATE_ACTIVE ? "n active" : " backup", + new_slave->link != BOND_LINK_DOWN ? "n up" : " down"); /* enslave is successful */ return 0; @@ -1742,227 +1576,12 @@ err_free: kfree(new_slave); - return err; -} - -/* - * This function changes the active slave to slave . - * It returns -EINVAL in the following cases. - * - is not found in the list. - * - There is not active slave now. - * - is already active. - * - The link state of is not BOND_LINK_UP. - * - is not running. - * In these cases, this fuction does nothing. - * In the other cases, currnt_slave pointer is changed and 0 is returned. - */ -static int bond_change_active(struct net_device *master_dev, struct net_device *slave_dev) -{ - bonding_t *bond; - slave_t *slave; - slave_t *oldactive = NULL; - slave_t *newactive = NULL; - int ret = 0; - - if (master_dev == NULL || slave_dev == NULL) { - return -ENODEV; - } - - /* Verify that master_dev is indeed the master of slave_dev */ - if (!(slave_dev->flags & IFF_SLAVE) || - (slave_dev->master != master_dev)) { - - return -EINVAL; - } - - bond = (struct bonding *) master_dev->priv; - write_lock_bh(&bond->lock); - slave = (slave_t *)bond; - oldactive = bond->current_slave; - - while ((slave = slave->prev) != (slave_t *)bond) { - if(slave_dev == slave->dev) { - newactive = slave; - break; - } - } - - /* - * Changing to the current active: do nothing; return success. - */ - if (newactive && (newactive == oldactive)) { - write_unlock_bh(&bond->lock); - return 0; - } - - if ((newactive != NULL)&& - (oldactive != NULL)&& - (newactive->link == BOND_LINK_UP)&& - IS_UP(newactive->dev)) { - change_active_interface(bond, newactive); - } else { - ret = -EINVAL; - } - write_unlock_bh(&bond->lock); - return ret; -} - -/** - * find_best_interface - select the best available slave to be the active one - * @bond: our bonding struct - * - * Warning: Caller must hold ptrlock for writing. - */ -static struct slave *find_best_interface(struct bonding *bond) -{ - struct slave *newslave, *oldslave; - struct slave *bestslave = NULL; - int mintime; - - newslave = oldslave = bond->current_slave; - - if (newslave == NULL) { /* there were no active slaves left */ - if (bond->next != (slave_t *)bond) { /* found one slave */ - newslave = bond->next; - } else { - return NULL; /* still no slave, return NULL */ - } - } - - mintime = updelay; - - /* first try the primary link; if arping, a link must tx/rx traffic - * before it can be considered the current_slave - also, we would skip - * slaves between the current_slave and primary_slave that may be up - * and able to arp - */ - if ((bond->primary_slave != NULL) && (arp_interval == 0)) { - if (IS_UP(bond->primary_slave->dev)) - newslave = bond->primary_slave; - } - - /* remember where to stop iterating over the slaves */ - oldslave = newslave; - - do { - if (IS_UP(newslave->dev)) { - if (newslave->link == BOND_LINK_UP) { - return newslave; - } - else if (newslave->link == BOND_LINK_BACK) { - /* link up, but waiting for stabilization */ - if (newslave->delay < mintime) { - mintime = newslave->delay; - bestslave = newslave; - } - } - } - } while ((newslave = newslave->next) != oldslave); - - return bestslave; -} - -/** - * change_active_interface - change the active slave into the specified one - * @bond: our bonding struct - * @new: the new slave to make the active one - * - * Set the new slave to the bond's settings and unset them on the old - * current_slave. - * Setting include flags, mc-list, promiscuity, allmulti, etc. - * - * If @new's link state is %BOND_LINK_BACK we'll set it to %BOND_LINK_UP, - * because it is apparently the best available slave we have, even though its - * updelay hasn't timed out yet. - * - * Warning: Caller must hold ptrlock for writing. - */ -static void change_active_interface(struct bonding *bond, struct slave *new) -{ - struct slave *old = bond->current_slave; - - if (old == new) { - return; - } - - if (new) { - if (new->link == BOND_LINK_BACK) { - if (USES_PRIMARY(bond_mode)) { - printk (KERN_INFO - "%s: making interface %s the new " - "active one %d ms earlier.\n", - bond->device->name, new->dev->name, - (updelay - new->delay) * miimon); - } - - new->delay = 0; - new->link = BOND_LINK_UP; - new->jiffies = jiffies; - - if (bond_mode == BOND_MODE_8023AD) { - bond_3ad_handle_link_change(new, BOND_LINK_UP); - } - - if ((bond_mode == BOND_MODE_TLB) || - (bond_mode == BOND_MODE_ALB)) { - bond_alb_handle_link_change(bond, new, BOND_LINK_UP); - } - } else { - if (USES_PRIMARY(bond_mode)) { - printk (KERN_INFO - "%s: making interface %s the new active one.\n", - bond->device->name, new->dev->name); - } - } - } - - if (bond_mode == BOND_MODE_ACTIVEBACKUP) { - if (old) { - bond_set_slave_inactive_flags(old); - } - - if (new) { - bond_set_slave_active_flags(new); - } - } - - if (USES_PRIMARY(bond_mode)) { - bond_mc_update(bond, new, old); - } - - if ((bond_mode == BOND_MODE_TLB) || - (bond_mode == BOND_MODE_ALB)) { - bond_alb_assign_current_slave(bond, new); - } else { - bond->current_slave = new; - } -} - -/** - * reselect_active_interface - select a new active slave, if needed - * @bond: our bonding struct - * - * This functions shoud be called when one of the following occurs: - * - The old current_slave has been released or lost its link. - * - The primary_slave has got its link back. - * - A slave has got its link back and there's no old current_slave. - * - * Warning: Caller must hold ptrlock for writing. - */ -static void reselect_active_interface(struct bonding *bond) -{ - struct slave *best_slave; - - best_slave = find_best_interface(bond); - - if (best_slave != bond->current_slave) { - change_active_interface(bond, best_slave); - } + return res; } /* * Try to release the slave device from the bond device - * It is legal to access current_slave without a lock because all the function + * It is legal to access curr_active_slave without a lock because all the function * is write-locked. * * The rules for slave state should be: @@ -1971,206 +1590,196 @@ * for Bonded connections: * The first up interface should be left on and all others downed. */ -static int bond_release(struct net_device *master, struct net_device *slave) +static int bond_release(struct net_device *bond_dev, struct net_device *slave_dev) { - bonding_t *bond; - slave_t *our_slave, *old_current; + struct bonding *bond = bond_dev->priv; + struct slave *slave, *oldcurrent; struct sockaddr addr; - - if (master == NULL || slave == NULL) { - return -ENODEV; + int mac_addr_differ; + + /* slave is not a slave or master is not master of this slave */ + if (!(slave_dev->flags & IFF_SLAVE) || + (slave_dev->master != bond_dev)) { + printk(KERN_ERR DRV_NAME + ": Error: %s: cannot release %s.\n", + bond_dev->name, slave_dev->name); + return -EINVAL; } - bond = (struct bonding *) master->priv; + write_lock_bh(&bond->lock); - /* master already enslaved, or slave not enslaved, - or no slave for this master */ - if ((master->flags & IFF_SLAVE) || !(slave->flags & IFF_SLAVE)) { - printk (KERN_DEBUG "%s: cannot release %s.\n", master->name, slave->name); + slave = bond_get_slave_by_dev(bond, slave_dev); + if (!slave) { + /* not a slave of this bond */ + printk(KERN_INFO DRV_NAME + ": %s: %s not enslaved\n", + bond_dev->name, slave_dev->name); return -EINVAL; } - write_lock_bh(&bond->lock); - bond->current_arp_slave = NULL; - our_slave = (slave_t *)bond; - old_current = bond->current_slave; - while ((our_slave = our_slave->prev) != (slave_t *)bond) { - if (our_slave->dev == slave) { - int mac_addr_differ = memcmp(bond->device->dev_addr, - our_slave->perm_hwaddr, - ETH_ALEN); - if (!mac_addr_differ && (bond->slave_cnt > 1)) { - printk(KERN_WARNING "WARNING: the permanent HWaddr of %s " - "- %02X:%02X:%02X:%02X:%02X:%02X - " - "is still in use by %s. Set the HWaddr " - "of %s to a different address " - "to avoid conflicts.\n", - slave->name, - our_slave->perm_hwaddr[0], - our_slave->perm_hwaddr[1], - our_slave->perm_hwaddr[2], - our_slave->perm_hwaddr[3], - our_slave->perm_hwaddr[4], - our_slave->perm_hwaddr[5], - bond->device->name, - slave->name); - } + mac_addr_differ = memcmp(bond_dev->dev_addr, + slave->perm_hwaddr, + ETH_ALEN); + if (!mac_addr_differ && (bond->slave_cnt > 1)) { + printk(KERN_WARNING DRV_NAME + ": Warning: the permanent HWaddr of %s " + "- %02X:%02X:%02X:%02X:%02X:%02X - is " + "still in use by %s. Set the HWaddr of " + "%s to a different address to avoid " + "conflicts.\n", + slave_dev->name, + slave->perm_hwaddr[0], + slave->perm_hwaddr[1], + slave->perm_hwaddr[2], + slave->perm_hwaddr[3], + slave->perm_hwaddr[4], + slave->perm_hwaddr[5], + bond_dev->name, + slave_dev->name); + } + + /* Inform AD package of unbinding of slave. */ + if (bond->params.mode == BOND_MODE_8023AD) { + /* must be called before the slave is + * detached from the list + */ + bond_3ad_unbind_slave(slave); + } - /* Inform AD package of unbinding of slave. */ - if (bond_mode == BOND_MODE_8023AD) { - /* must be called before the slave is - * detached from the list - */ - bond_3ad_unbind_slave(our_slave); - } + printk(KERN_INFO DRV_NAME + ": %s: releasing %s interface %s\n", + bond_dev->name, + (slave->state == BOND_STATE_ACTIVE) + ? "active" : "backup", + slave_dev->name); - printk (KERN_INFO "%s: releasing %s interface %s\n", - master->name, - (our_slave->state == BOND_STATE_ACTIVE) ? "active" : "backup", - slave->name); + oldcurrent = bond->curr_active_slave; - /* release the slave from its bond */ - bond_detach_slave(bond, our_slave); + bond->current_arp_slave = NULL; - if (bond->primary_slave == our_slave) { - bond->primary_slave = NULL; - } + /* release the slave from its bond */ + bond_detach_slave(bond, slave); - if (bond->current_slave == our_slave) { - change_active_interface(bond, NULL); - reselect_active_interface(bond); - } + if (bond->primary_slave == slave) { + bond->primary_slave = NULL; + } - if (bond->current_slave == NULL) { - printk(KERN_INFO - "%s: now running without any active interface !\n", - master->name); - } + if (oldcurrent == slave) { + bond_change_active_slave(bond, NULL); + } - if ((bond_mode == BOND_MODE_TLB) || - (bond_mode == BOND_MODE_ALB)) { - /* must be called only after the slave has been - * detached from the list and the current_slave - * has been replaced (if our_slave == old_current) - */ - bond_alb_deinit_slave(bond, our_slave); - } + if ((bond->params.mode == BOND_MODE_TLB) || + (bond->params.mode == BOND_MODE_ALB)) { + /* Must be called only after the slave has been + * detached from the list and the curr_active_slave + * has been cleared (if our_slave == old_current), + * but before a new active slave is selected. + */ + bond_alb_deinit_slave(bond, slave); + } - break; - } + if (oldcurrent == slave) { + bond_select_active_slave(bond); + if (!bond->curr_active_slave) { + printk(KERN_INFO DRV_NAME + ": %s: now running without any active " + "interface !\n", + bond_dev->name); + } } + write_unlock_bh(&bond->lock); - - if (our_slave == (slave_t *)bond) { - /* if we get here, it's because the device was not found */ - printk (KERN_INFO "%s: %s not enslaved\n", master->name, slave->name); - return -EINVAL; - } - /* unset promiscuity level from slave */ - if (master->flags & IFF_PROMISC) { - /* If the mode USES_PRIMARY, then we should only remove its - * promisc settings if it was the current_slave, but that was - * already taken care of above when we detached the slave - */ - if (!USES_PRIMARY(bond_mode)) { - dev_set_promiscuity(slave, -1); + /* If the mode USES_PRIMARY, then we should only remove its + * promisc and mc settings if it was the curr_active_slave, but that was + * already taken care of above when we detached the slave + */ + if (!USES_PRIMARY(bond->params.mode)) { + /* unset promiscuity level from slave */ + if (bond_dev->flags & IFF_PROMISC) { + dev_set_promiscuity(slave_dev, -1); } - } - /* undo settings and restore original values */ - if (multicast_mode == BOND_MULTICAST_ALL) { - /* flush master's mc_list from slave */ - bond_mc_list_flush (slave, master); + /* unset allmulti level from slave */ + if (bond_dev->flags & IFF_ALLMULTI) { + dev_set_allmulti(slave_dev, -1); + } - /* unset allmulti level from slave */ - if (master->flags & IFF_ALLMULTI) - dev_set_allmulti(slave, -1); + /* flush master's mc_list from slave */ + bond_mc_list_flush(bond_dev, slave_dev); } - netdev_set_master(slave, NULL); + netdev_set_master(slave_dev, NULL); /* close slave before restoring its mac address */ - dev_close(slave); + dev_close(slave_dev); if (app_abi_ver >= 1) { /* restore original ("permanent") mac address */ - memcpy(addr.sa_data, our_slave->perm_hwaddr, ETH_ALEN); - addr.sa_family = slave->type; - slave->set_mac_address(slave, &addr); + memcpy(addr.sa_data, slave->perm_hwaddr, ETH_ALEN); + addr.sa_family = slave_dev->type; + slave_dev->set_mac_address(slave_dev, &addr); } /* restore the original state of the * IFF_NOARP flag that might have been * set by bond_set_slave_inactive_flags() */ - if ((our_slave->original_flags & IFF_NOARP) == 0) { - slave->flags &= ~IFF_NOARP; + if ((slave->original_flags & IFF_NOARP) == 0) { + slave_dev->flags &= ~IFF_NOARP; } - kfree(our_slave); + kfree(slave); /* if the last slave was removed, zero the mac address * of the master so it will be set by the application * to the mac address of the first slave */ - if (bond->next == (slave_t*)bond) { - memset(master->dev_addr, 0, master->addr_len); + if (bond->slave_cnt == 0) { + memset(bond_dev->dev_addr, 0, bond_dev->addr_len); } return 0; /* deletion OK */ } -/* +/* * This function releases all slaves. */ -static int bond_release_all(struct net_device *master) +static int bond_release_all(struct net_device *bond_dev) { - bonding_t *bond; - slave_t *our_slave, *old_current; + struct bonding *bond = bond_dev->priv; + struct slave *slave; struct net_device *slave_dev; struct sockaddr addr; - int err = 0; - - if (master == NULL) { - return -ENODEV; - } - - if (master->flags & IFF_SLAVE) { - return -EINVAL; - } - - bond = (struct bonding *) master->priv; write_lock_bh(&bond->lock); - if (bond->next == (struct slave *) bond) { - err = -EINVAL; + + if (bond->slave_cnt == 0) { goto out; } - old_current = bond->current_slave; - change_active_interface(bond, NULL); bond->current_arp_slave = NULL; bond->primary_slave = NULL; + bond_change_active_slave(bond, NULL); - while ((our_slave = bond->prev) != (slave_t *)bond) { + while ((slave = bond->first_slave) != NULL) { /* Inform AD package of unbinding of slave * before slave is detached from the list. */ - if (bond_mode == BOND_MODE_8023AD) { - bond_3ad_unbind_slave(our_slave); + if (bond->params.mode == BOND_MODE_8023AD) { + bond_3ad_unbind_slave(slave); } - slave_dev = our_slave->dev; - bond_detach_slave(bond, our_slave); + slave_dev = slave->dev; + bond_detach_slave(bond, slave); - if ((bond_mode == BOND_MODE_TLB) || - (bond_mode == BOND_MODE_ALB)) { + if ((bond->params.mode == BOND_MODE_TLB) || + (bond->params.mode == BOND_MODE_ALB)) { /* must be called only after the slave * has been detached from the list */ - bond_alb_deinit_slave(bond, our_slave); + bond_alb_deinit_slave(bond, slave); } /* now that the slave is detached, unlock and perform @@ -2179,20 +1788,23 @@ */ write_unlock_bh(&bond->lock); - /* unset promiscuity level from slave */ - if (master->flags & IFF_PROMISC) { - if (!USES_PRIMARY(bond_mode)) { - dev_set_promiscuity(slave_dev, -1); + /* If the mode USES_PRIMARY, then we should only remove its + * promisc and mc settings if it was the curr_active_slave, but that was + * already taken care of above when we detached the slave + */ + if (!USES_PRIMARY(bond->params.mode)) { + /* unset promiscuity level from slave */ + if (bond_dev->flags & IFF_PROMISC) { + dev_set_promiscuity(slave_dev, -1); } - } - if (multicast_mode == BOND_MULTICAST_ALL) { - /* flush master's mc_list from slave */ - bond_mc_list_flush (slave_dev, master); - - /* unset allmulti level from slave */ - if (master->flags & IFF_ALLMULTI) - dev_set_allmulti(slave_dev, -1); + /* unset allmulti level from slave */ + if (bond_dev->flags & IFF_ALLMULTI) { + dev_set_allmulti(slave_dev, -1); + } + + /* flush master's mc_list from slave */ + bond_mc_list_flush(bond_dev, slave_dev); } netdev_set_master(slave_dev, NULL); @@ -2202,7 +1814,7 @@ if (app_abi_ver >= 1) { /* restore original ("permanent") mac address*/ - memcpy(addr.sa_data, our_slave->perm_hwaddr, ETH_ALEN); + memcpy(addr.sa_data, slave->perm_hwaddr, ETH_ALEN); addr.sa_family = slave_dev->type; slave_dev->set_mac_address(slave_dev, &addr); } @@ -2210,11 +1822,11 @@ /* restore the original state of the IFF_NOARP flag that might have * been set by bond_set_slave_inactive_flags() */ - if ((our_slave->original_flags & IFF_NOARP) == 0) { + if ((slave->original_flags & IFF_NOARP) == 0) { slave_dev->flags &= ~IFF_NOARP; } - kfree(our_slave); + kfree(slave); /* re-acquire the lock before getting the next slave */ write_lock_bh(&bond->lock); @@ -2224,72 +1836,240 @@ * set by the application to the mac address of the * first slave */ - memset(master->dev_addr, 0, master->addr_len); + memset(bond_dev->dev_addr, 0, bond_dev->addr_len); - printk (KERN_INFO "%s: released all slaves\n", master->name); + printk(KERN_INFO DRV_NAME + ": %s: released all slaves\n", + bond_dev->name); out: write_unlock_bh(&bond->lock); - return err; + return 0; +} + +/* + * This function changes the active slave to slave . + * It returns -EINVAL in the following cases. + * - is not found in the list. + * - There is not active slave now. + * - is already active. + * - The link state of is not BOND_LINK_UP. + * - is not running. + * In these cases, this fuction does nothing. + * In the other cases, currnt_slave pointer is changed and 0 is returned. + */ +static int bond_ioctl_change_active(struct net_device *bond_dev, struct net_device *slave_dev) +{ + struct bonding *bond = bond_dev->priv; + struct slave *old_active = NULL; + struct slave *new_active = NULL; + int res = 0; + + if (!USES_PRIMARY(bond->params.mode)) { + return -EINVAL; + } + + /* Verify that master_dev is indeed the master of slave_dev */ + if (!(slave_dev->flags & IFF_SLAVE) || + (slave_dev->master != bond_dev)) { + return -EINVAL; + } + + write_lock_bh(&bond->lock); + + old_active = bond->curr_active_slave; + new_active = bond_get_slave_by_dev(bond, slave_dev); + + /* + * Changing to the current active: do nothing; return success. + */ + if (new_active && (new_active == old_active)) { + write_unlock_bh(&bond->lock); + return 0; + } + + if ((new_active) && + (old_active) && + (new_active->link == BOND_LINK_UP) && + IS_UP(new_active->dev)) { + bond_change_active_slave(bond, new_active); + } else { + res = -EINVAL; + } + + write_unlock_bh(&bond->lock); + + return res; } +static int bond_ethtool_ioctl(struct net_device *bond_dev, struct ifreq *ifr) +{ + struct ethtool_drvinfo info; + void *addr = ifr->ifr_data; + uint32_t cmd; + + if (get_user(cmd, (uint32_t *)addr)) { + return -EFAULT; + } + + switch (cmd) { + case ETHTOOL_GDRVINFO: + if (copy_from_user(&info, addr, sizeof(info))) { + return -EFAULT; + } + + if (strcmp(info.driver, "ifenslave") == 0) { + int new_abi_ver; + char *endptr; + + new_abi_ver = simple_strtoul(info.fw_version, + &endptr, 0); + if (*endptr) { + printk(KERN_ERR DRV_NAME + ": Error: got invalid ABI " + "version from application\n"); + + return -EINVAL; + } + + if (orig_app_abi_ver == -1) { + orig_app_abi_ver = new_abi_ver; + } + + app_abi_ver = new_abi_ver; + } + + strncpy(info.driver, DRV_NAME, 32); + strncpy(info.version, DRV_VERSION, 32); + snprintf(info.fw_version, 32, "%d", BOND_ABI_VERSION); + + if (copy_to_user(addr, &info, sizeof(info))) { + return -EFAULT; + } + + return 0; + default: + return -EOPNOTSUPP; + } +} + +static int bond_info_query(struct net_device *bond_dev, struct ifbond *info) +{ + struct bonding *bond = bond_dev->priv; + + info->bond_mode = bond->params.mode; + info->miimon = bond->params.miimon; + + read_lock_bh(&bond->lock); + info->num_slaves = bond->slave_cnt; + read_unlock_bh(&bond->lock); + + return 0; +} + +static int bond_slave_info_query(struct net_device *bond_dev, struct ifslave *info) +{ + struct bonding *bond = bond_dev->priv; + struct slave *slave; + int i, found = 0; + + if (info->slave_id < 0) { + return -ENODEV; + } + + read_lock_bh(&bond->lock); + + bond_for_each_slave(bond, slave, i) { + if (i == (int)info->slave_id) { + found = 1; + break; + } + } + + read_unlock_bh(&bond->lock); + + if (found) { + strcpy(info->slave_name, slave->dev->name); + info->link = slave->link; + info->state = slave->state; + info->link_failure_count = slave->link_failure_count; + } else { + return -ENODEV; + } + + return 0; +} + +/*-------------------------------- Monitoring -------------------------------*/ + /* this function is called regularly to monitor each slave's link. */ -static void bond_mii_monitor(struct net_device *master) +static void bond_mii_monitor(struct net_device *bond_dev) { - bonding_t *bond = (struct bonding *) master->priv; - slave_t *slave, *oldcurrent; - int slave_died = 0; + struct bonding *bond = bond_dev->priv; + struct slave *slave, *oldcurrent; int do_failover = 0; + int delta_in_ticks; + int i; read_lock(&bond->lock); + delta_in_ticks = (bond->params.miimon * HZ) / 1000; + + if (bond->kill_timers) { + goto out; + } + + if (bond->slave_cnt == 0) { + goto re_arm; + } + /* we will try to read the link status of each of our slaves, and * set their IFF_RUNNING flag appropriately. For each slave not * supporting MII status, we won't do anything so that a user-space * program could monitor the link itself if needed. */ - slave = (slave_t *)bond; + read_lock(&bond->curr_slave_lock); + oldcurrent = bond->curr_active_slave; + read_unlock(&bond->curr_slave_lock); - read_lock(&bond->ptrlock); - oldcurrent = bond->current_slave; - read_unlock(&bond->ptrlock); - - while ((slave = slave->prev) != (slave_t *)bond) { - struct net_device *dev = slave->dev; + bond_for_each_slave(bond, slave, i) { + struct net_device *slave_dev = slave->dev; int link_state; u16 old_speed = slave->speed; u8 old_duplex = slave->duplex; - - link_state = bond_check_dev_link(dev, 0); + + link_state = bond_check_dev_link(bond, slave_dev, 0); switch (slave->link) { case BOND_LINK_UP: /* the link was up */ if (link_state == BMSR_LSTATUS) { /* link stays up, nothing more to do */ break; - } - else { /* link going down */ + } else { /* link going down */ slave->link = BOND_LINK_FAIL; - slave->delay = downdelay; + slave->delay = bond->params.downdelay; + if (slave->link_failure_count < UINT_MAX) { slave->link_failure_count++; } - if (downdelay > 0) { - printk (KERN_INFO - "%s: link status down for %sinterface " - "%s, disabling it in %d ms.\n", - master->name, - IS_UP(dev) - ? ((bond_mode == BOND_MODE_ACTIVEBACKUP) - ? ((slave == oldcurrent) - ? "active " : "backup ") - : "") - : "idle ", - dev->name, - downdelay * miimon); - } + + if (bond->params.downdelay) { + printk(KERN_INFO DRV_NAME + ": %s: link status down for %s " + "interface %s, disabling it in " + "%d ms.\n", + bond_dev->name, + IS_UP(slave_dev) + ? ((bond->params.mode == BOND_MODE_ACTIVEBACKUP) + ? ((slave == oldcurrent) + ? "active " : "backup ") + : "") + : "idle ", + slave_dev->name, + bond->params.downdelay * bond->params.miimon); + } } /* no break ! fall through the BOND_LINK_FAIL test to ensure proper action to be taken @@ -2300,35 +2080,35 @@ if (slave->delay <= 0) { /* link down for too long time */ slave->link = BOND_LINK_DOWN; + /* in active/backup mode, we must * completely disable this interface */ - if ((bond_mode == BOND_MODE_ACTIVEBACKUP) || - (bond_mode == BOND_MODE_8023AD)) { + if ((bond->params.mode == BOND_MODE_ACTIVEBACKUP) || + (bond->params.mode == BOND_MODE_8023AD)) { bond_set_slave_inactive_flags(slave); } - printk(KERN_INFO - "%s: link status definitely down " - "for interface %s, disabling it", - master->name, - dev->name); + printk(KERN_INFO DRV_NAME + ": %s: link status definitely " + "down for interface %s, " + "disabling it\n", + bond_dev->name, + slave_dev->name); /* notify ad that the link status has changed */ - if (bond_mode == BOND_MODE_8023AD) { + if (bond->params.mode == BOND_MODE_8023AD) { bond_3ad_handle_link_change(slave, BOND_LINK_DOWN); } - if ((bond_mode == BOND_MODE_TLB) || - (bond_mode == BOND_MODE_ALB)) { + if ((bond->params.mode == BOND_MODE_TLB) || + (bond->params.mode == BOND_MODE_ALB)) { bond_alb_handle_link_change(bond, slave, BOND_LINK_DOWN); } if (slave == oldcurrent) { do_failover = 1; } - - slave_died = 1; } else { slave->delay--; } @@ -2336,12 +2116,12 @@ /* link up again */ slave->link = BOND_LINK_UP; slave->jiffies = jiffies; - printk(KERN_INFO - "%s: link status up again after %d ms " - "for interface %s.\n", - master->name, - (downdelay - slave->delay) * miimon, - dev->name); + printk(KERN_INFO DRV_NAME + ": %s: link status up again after %d " + "ms for interface %s.\n", + bond_dev->name, + (bond->params.downdelay - slave->delay) * bond->params.miimon, + slave_dev->name); } break; case BOND_LINK_DOWN: /* the link was down */ @@ -2350,17 +2130,18 @@ break; } else { /* link going up */ slave->link = BOND_LINK_BACK; - slave->delay = updelay; - - if (updelay > 0) { + slave->delay = bond->params.updelay; + + if (bond->params.updelay) { /* if updelay == 0, no need to advertise about a 0 ms delay */ - printk (KERN_INFO - "%s: link status up for interface" - " %s, enabling it in %d ms.\n", - master->name, - dev->name, - updelay * miimon); + printk(KERN_INFO DRV_NAME + ": %s: link status up for " + "interface %s, enabling it " + "in %d ms.\n", + bond_dev->name, + slave_dev->name, + bond->params.updelay * bond->params.miimon); } } /* no break ! fall through the BOND_LINK_BACK state in @@ -2370,12 +2151,13 @@ if (link_state != BMSR_LSTATUS) { /* link down again */ slave->link = BOND_LINK_DOWN; - printk(KERN_INFO - "%s: link status down again after %d ms " - "for interface %s.\n", - master->name, - (updelay - slave->delay) * miimon, - dev->name); + + printk(KERN_INFO DRV_NAME + ": %s: link status down again after %d " + "ms for interface %s.\n", + bond_dev->name, + (bond->params.updelay - slave->delay) * bond->params.miimon, + slave_dev->name); } else { /* link stays up */ if (slave->delay == 0) { @@ -2383,11 +2165,10 @@ slave->link = BOND_LINK_UP; slave->jiffies = jiffies; - if (bond_mode == BOND_MODE_8023AD) { + if (bond->params.mode == BOND_MODE_8023AD) { /* prevent it from being the active one */ slave->state = BOND_STATE_BACKUP; - } - else if (bond_mode != BOND_MODE_ACTIVEBACKUP) { + } else if (bond->params.mode != BOND_MODE_ACTIVEBACKUP) { /* make it immediately active */ slave->state = BOND_STATE_ACTIVE; } else if (slave != bond->primary_slave) { @@ -2395,23 +2176,23 @@ slave->state = BOND_STATE_BACKUP; } - printk(KERN_INFO - "%s: link status definitely up " - "for interface %s.\n", - master->name, - dev->name); - + printk(KERN_INFO DRV_NAME + ": %s: link status definitely " + "up for interface %s.\n", + bond_dev->name, + slave_dev->name); + /* notify ad that the link status has changed */ - if (bond_mode == BOND_MODE_8023AD) { + if (bond->params.mode == BOND_MODE_8023AD) { bond_3ad_handle_link_change(slave, BOND_LINK_UP); } - if ((bond_mode == BOND_MODE_TLB) || - (bond_mode == BOND_MODE_ALB)) { + if ((bond->params.mode == BOND_MODE_TLB) || + (bond->params.mode == BOND_MODE_ALB)) { bond_alb_handle_link_change(bond, slave, BOND_LINK_UP); } - if ((oldcurrent == NULL) || + if ((!oldcurrent) || (slave == bond->primary_slave)) { do_failover = 1; } @@ -2420,120 +2201,128 @@ } } break; - } /* end of switch */ + default: + /* Should not happen */ + printk(KERN_ERR "bonding: Error: %s Illegal value (link=%d)\n", + slave->dev->name, slave->link); + goto out; + } /* end of switch (slave->link) */ bond_update_speed_duplex(slave); - if (bond_mode == BOND_MODE_8023AD) { + if (bond->params.mode == BOND_MODE_8023AD) { if (old_speed != slave->speed) { bond_3ad_adapter_speed_changed(slave); } + if (old_duplex != slave->duplex) { bond_3ad_adapter_duplex_changed(slave); } } - } /* end of while */ + } /* end of for */ if (do_failover) { - write_lock(&bond->ptrlock); + write_lock(&bond->curr_slave_lock); - reselect_active_interface(bond); - if (oldcurrent && !bond->current_slave) { - printk(KERN_INFO - "%s: now running without any active interface !\n", - master->name); + bond_select_active_slave(bond); + + if (oldcurrent && !bond->curr_active_slave) { + printk(KERN_INFO DRV_NAME + ": %s: now running without any active " + "interface !\n", + bond_dev->name); } - write_unlock(&bond->ptrlock); + write_unlock(&bond->curr_slave_lock); } +re_arm: + if (bond->params.miimon) { + mod_timer(&bond->mii_timer, jiffies + delta_in_ticks); + } +out: read_unlock(&bond->lock); - /* re-arm the timer */ - mod_timer(&bond->mii_timer, jiffies + (miimon * HZ / 1000)); } -/* - * this function is called regularly to monitor each slave's link +static void bond_arp_send_all(struct bonding *bond, struct slave *slave) +{ + int i; + u32 *targets = bond->params.arp_targets; + + for (i = 0; (i < BOND_MAX_ARP_TARGETS) && targets[i]; i++) { + arp_send(ARPOP_REQUEST, ETH_P_ARP, targets[i], slave->dev, + my_ip, NULL, slave->dev->dev_addr, + NULL); + } +} + +/* + * this function is called regularly to monitor each slave's link * ensuring that traffic is being sent and received when arp monitoring - * is used in load-balancing mode. if the adapter has been dormant, then an - * arp is transmitted to generate traffic. see activebackup_arp_monitor for - * arp monitoring in active backup mode. + * is used in load-balancing mode. if the adapter has been dormant, then an + * arp is transmitted to generate traffic. see activebackup_arp_monitor for + * arp monitoring in active backup mode. */ -static void loadbalance_arp_monitor(struct net_device *master) +static void bond_loadbalance_arp_mon(struct net_device *bond_dev) { - bonding_t *bond; - slave_t *slave, *oldcurrent; - int the_delta_in_ticks = arp_interval * HZ / 1000; - int next_timer = jiffies + (arp_interval * HZ / 1000); + struct bonding *bond = bond_dev->priv; + struct slave *slave, *oldcurrent; int do_failover = 0; + int delta_in_ticks; + int i; - bond = (struct bonding *) master->priv; - if (master->priv == NULL) { - mod_timer(&bond->arp_timer, next_timer); - return; - } + read_lock(&bond->lock); - /* TODO: investigate why rtnl_shlock_nowait and rtnl_exlock_nowait - * are called below and add comment why they are required... - */ - if ((!IS_UP(master)) || rtnl_shlock_nowait()) { - mod_timer(&bond->arp_timer, next_timer); - return; - } + delta_in_ticks = (bond->params.arp_interval * HZ) / 1000; - if (rtnl_exlock_nowait()) { - rtnl_shunlock(); - mod_timer(&bond->arp_timer, next_timer); - return; + if (bond->kill_timers) { + goto out; } - read_lock(&bond->lock); + if (bond->slave_cnt == 0) { + goto re_arm; + } - read_lock(&bond->ptrlock); - oldcurrent = bond->current_slave; - read_unlock(&bond->ptrlock); + read_lock(&bond->curr_slave_lock); + oldcurrent = bond->curr_active_slave; + read_unlock(&bond->curr_slave_lock); /* see if any of the previous devices are up now (i.e. they have - * xmt and rcv traffic). the current_slave does not come into + * xmt and rcv traffic). the curr_active_slave does not come into * the picture unless it is null. also, slave->jiffies is not needed * here because we send an arp on each slave and give a slave as * long as it needs to get the tx/rx within the delta. * TODO: what about up/down delay in arp mode? it wasn't here before - * so it can wait + * so it can wait */ - slave = (slave_t *)bond; - while ((slave = slave->prev) != (slave_t *)bond) { - - if (slave->link != BOND_LINK_UP) { - - if (((jiffies - slave->dev->trans_start) <= - the_delta_in_ticks) && - ((jiffies - slave->dev->last_rx) <= - the_delta_in_ticks)) { + bond_for_each_slave(bond, slave, i) { + if (slave->link != BOND_LINK_UP) { + if (((jiffies - slave->dev->trans_start) <= delta_in_ticks) && + ((jiffies - slave->dev->last_rx) <= delta_in_ticks)) { slave->link = BOND_LINK_UP; slave->state = BOND_STATE_ACTIVE; /* primary_slave has no meaning in round-robin - * mode. the window of a slave being up and - * current_slave being null after enslaving + * mode. the window of a slave being up and + * curr_active_slave being null after enslaving * is closed. */ - if (oldcurrent == NULL) { - printk(KERN_INFO - "%s: link status definitely up " - "for interface %s, ", - master->name, - slave->dev->name); + if (!oldcurrent) { + printk(KERN_INFO DRV_NAME + ": %s: link status definitely " + "up for interface %s, ", + bond_dev->name, + slave->dev->name); do_failover = 1; } else { - printk(KERN_INFO - "%s: interface %s is now up\n", - master->name, - slave->dev->name); + printk(KERN_INFO DRV_NAME + ": %s: interface %s is now up\n", + bond_dev->name, + slave->dev->name); } - } + } } else { /* slave->link == BOND_LINK_UP */ @@ -2541,224 +2330,237 @@ * when the source ip is 0, so don't take the link down * if we don't know our ip yet */ - if (((jiffies - slave->dev->trans_start) >= - (2*the_delta_in_ticks)) || - (((jiffies - slave->dev->last_rx) >= - (2*the_delta_in_ticks)) && my_ip !=0)) { + if (((jiffies - slave->dev->trans_start) >= (2*delta_in_ticks)) || + (((jiffies - slave->dev->last_rx) >= (2*delta_in_ticks)) && + my_ip)) { + slave->link = BOND_LINK_DOWN; slave->state = BOND_STATE_BACKUP; + if (slave->link_failure_count < UINT_MAX) { slave->link_failure_count++; } - printk(KERN_INFO - "%s: interface %s is now down.\n", - master->name, + + printk(KERN_INFO DRV_NAME + ": %s: interface %s is now down.\n", + bond_dev->name, slave->dev->name); if (slave == oldcurrent) { do_failover = 1; } } - } + } - /* note: if switch is in round-robin mode, all links + /* note: if switch is in round-robin mode, all links * must tx arp to ensure all links rx an arp - otherwise - * links may oscillate or not come up at all; if switch is - * in something like xor mode, there is nothing we can - * do - all replies will be rx'ed on same link causing slaves + * links may oscillate or not come up at all; if switch is + * in something like xor mode, there is nothing we can + * do - all replies will be rx'ed on same link causing slaves * to be unstable during low/no traffic periods */ if (IS_UP(slave->dev)) { - arp_send_all(slave); + bond_arp_send_all(bond, slave); } } if (do_failover) { - write_lock(&bond->ptrlock); + write_lock(&bond->curr_slave_lock); - reselect_active_interface(bond); - if (oldcurrent && !bond->current_slave) { - printk(KERN_INFO - "%s: now running without any active interface !\n", - master->name); + bond_select_active_slave(bond); + + if (oldcurrent && !bond->curr_active_slave) { + printk(KERN_INFO DRV_NAME + ": %s: now running without any active " + "interface !\n", + bond_dev->name); } - write_unlock(&bond->ptrlock); + write_unlock(&bond->curr_slave_lock); } +re_arm: + if (bond->params.arp_interval) { + mod_timer(&bond->arp_timer, jiffies + delta_in_ticks); + } +out: read_unlock(&bond->lock); - rtnl_exunlock(); - rtnl_shunlock(); - - /* re-arm the timer */ - mod_timer(&bond->arp_timer, next_timer); } -/* +/* * When using arp monitoring in active-backup mode, this function is * called to determine if any backup slaves have went down or a new * current slave needs to be found. - * The backup slaves never generate traffic, they are considered up by merely - * receiving traffic. If the current slave goes down, each backup slave will - * be given the opportunity to tx/rx an arp before being taken down - this - * prevents all slaves from being taken down due to the current slave not + * The backup slaves never generate traffic, they are considered up by merely + * receiving traffic. If the current slave goes down, each backup slave will + * be given the opportunity to tx/rx an arp before being taken down - this + * prevents all slaves from being taken down due to the current slave not * sending any traffic for the backups to receive. The arps are not necessarily - * necessary, any tx and rx traffic will keep the current slave up. While any - * rx traffic will keep the backup slaves up, the current slave is responsible - * for generating traffic to keep them up regardless of any other traffic they + * necessary, any tx and rx traffic will keep the current slave up. While any + * rx traffic will keep the backup slaves up, the current slave is responsible + * for generating traffic to keep them up regardless of any other traffic they * may have received. * see loadbalance_arp_monitor for arp monitoring in load balancing mode */ -static void activebackup_arp_monitor(struct net_device *master) +static void bond_activebackup_arp_mon(struct net_device *bond_dev) { - bonding_t *bond; - slave_t *slave; - int the_delta_in_ticks = arp_interval * HZ / 1000; - int next_timer = jiffies + (arp_interval * HZ / 1000); - - bond = (struct bonding *) master->priv; - if (master->priv == NULL) { - mod_timer(&bond->arp_timer, next_timer); - return; - } + struct bonding *bond = bond_dev->priv; + struct slave *slave; + int delta_in_ticks; + int i; - if (!IS_UP(master)) { - mod_timer(&bond->arp_timer, next_timer); - return; + read_lock(&bond->lock); + + delta_in_ticks = (bond->params.arp_interval * HZ) / 1000; + + if (bond->kill_timers) { + goto out; } - read_lock(&bond->lock); + if (bond->slave_cnt == 0) { + goto re_arm; + } - /* determine if any slave has come up or any backup slave has - * gone down + /* determine if any slave has come up or any backup slave has + * gone down * TODO: what about up/down delay in arp mode? it wasn't here before - * so it can wait + * so it can wait */ - slave = (slave_t *)bond; - while ((slave = slave->prev) != (slave_t *)bond) { - - if (slave->link != BOND_LINK_UP) { - if ((jiffies - slave->dev->last_rx) <= - the_delta_in_ticks) { + bond_for_each_slave(bond, slave, i) { + if (slave->link != BOND_LINK_UP) { + if ((jiffies - slave->dev->last_rx) <= delta_in_ticks) { slave->link = BOND_LINK_UP; - write_lock(&bond->ptrlock); - if ((bond->current_slave == NULL) && - ((jiffies - slave->dev->trans_start) <= - the_delta_in_ticks)) { - change_active_interface(bond, slave); + + write_lock(&bond->curr_slave_lock); + + if ((!bond->curr_active_slave) && + ((jiffies - slave->dev->trans_start) <= delta_in_ticks)) { + bond_change_active_slave(bond, slave); bond->current_arp_slave = NULL; - } else if (bond->current_slave != slave) { - /* this slave has just come up but we + } else if (bond->curr_active_slave != slave) { + /* this slave has just come up but we * already have a current slave; this * can also happen if bond_enslave adds - * a new slave that is up while we are + * a new slave that is up while we are * searching for a new slave */ bond_set_slave_inactive_flags(slave); bond->current_arp_slave = NULL; } - if (slave == bond->current_slave) { - printk(KERN_INFO - "%s: %s is up and now the " - "active interface\n", - master->name, - slave->dev->name); + if (slave == bond->curr_active_slave) { + printk(KERN_INFO DRV_NAME + ": %s: %s is up and now the " + "active interface\n", + bond_dev->name, + slave->dev->name); } else { - printk(KERN_INFO - "%s: backup interface %s is " - "now up\n", - master->name, - slave->dev->name); + printk(KERN_INFO DRV_NAME + ": %s: backup interface %s is " + "now up\n", + bond_dev->name, + slave->dev->name); } - write_unlock(&bond->ptrlock); + write_unlock(&bond->curr_slave_lock); } } else { - read_lock(&bond->ptrlock); - if ((slave != bond->current_slave) && - (bond->current_arp_slave == NULL) && - (((jiffies - slave->dev->last_rx) >= - 3*the_delta_in_ticks) && (my_ip != 0))) { - /* a backup slave has gone down; three times - * the delta allows the current slave to be + read_lock(&bond->curr_slave_lock); + + if ((slave != bond->curr_active_slave) && + (!bond->current_arp_slave) && + (((jiffies - slave->dev->last_rx) >= 3*delta_in_ticks) && + my_ip)) { + /* a backup slave has gone down; three times + * the delta allows the current slave to be * taken out before the backup slave. * note: a non-null current_arp_slave indicates - * the current_slave went down and we are - * searching for a new one; under this - * condition we only take the current_slave - * down - this gives each slave a chance to + * the curr_active_slave went down and we are + * searching for a new one; under this + * condition we only take the curr_active_slave + * down - this gives each slave a chance to * tx/rx traffic before being taken out */ - read_unlock(&bond->ptrlock); + + read_unlock(&bond->curr_slave_lock); + slave->link = BOND_LINK_DOWN; + if (slave->link_failure_count < UINT_MAX) { slave->link_failure_count++; } + bond_set_slave_inactive_flags(slave); - printk(KERN_INFO - "%s: backup interface %s is now down\n", - master->name, - slave->dev->name); + + printk(KERN_INFO DRV_NAME + ": %s: backup interface %s is now down\n", + bond_dev->name, + slave->dev->name); } else { - read_unlock(&bond->ptrlock); + read_unlock(&bond->curr_slave_lock); } } } - read_lock(&bond->ptrlock); - slave = bond->current_slave; - read_unlock(&bond->ptrlock); - - if (slave != NULL) { + read_lock(&bond->curr_slave_lock); + slave = bond->curr_active_slave; + read_unlock(&bond->curr_slave_lock); + if (slave) { /* if we have sent traffic in the past 2*arp_intervals but - * haven't xmit and rx traffic in that time interval, select + * haven't xmit and rx traffic in that time interval, select * a different slave. slave->jiffies is only updated when - * a slave first becomes the current_slave - not necessarily - * after every arp; this ensures the slave has a full 2*delta - * before being taken out. if a primary is being used, check - * if it is up and needs to take over as the current_slave + * a slave first becomes the curr_active_slave - not necessarily + * after every arp; this ensures the slave has a full 2*delta + * before being taken out. if a primary is being used, check + * if it is up and needs to take over as the curr_active_slave */ - if ((((jiffies - slave->dev->trans_start) >= - (2*the_delta_in_ticks)) || - (((jiffies - slave->dev->last_rx) >= - (2*the_delta_in_ticks)) && (my_ip != 0))) && - ((jiffies - slave->jiffies) >= 2*the_delta_in_ticks)) { + if ((((jiffies - slave->dev->trans_start) >= (2*delta_in_ticks)) || + (((jiffies - slave->dev->last_rx) >= (2*delta_in_ticks)) && + my_ip)) && + ((jiffies - slave->jiffies) >= 2*delta_in_ticks)) { slave->link = BOND_LINK_DOWN; + if (slave->link_failure_count < UINT_MAX) { slave->link_failure_count++; } - printk(KERN_INFO "%s: link status down for " - "active interface %s, disabling it", - master->name, + + printk(KERN_INFO DRV_NAME + ": %s: link status down for active interface " + "%s, disabling it\n", + bond_dev->name, slave->dev->name); - write_lock(&bond->ptrlock); - reselect_active_interface(bond); - slave = bond->current_slave; - write_unlock(&bond->ptrlock); + + write_lock(&bond->curr_slave_lock); + + bond_select_active_slave(bond); + slave = bond->curr_active_slave; + + write_unlock(&bond->curr_slave_lock); + bond->current_arp_slave = slave; - if (slave != NULL) { + + if (slave) { slave->jiffies = jiffies; } - - } else if ((bond->primary_slave != NULL) && - (bond->primary_slave != slave) && + } else if ((bond->primary_slave) && + (bond->primary_slave != slave) && (bond->primary_slave->link == BOND_LINK_UP)) { - /* at this point, slave is the current_slave */ - printk(KERN_INFO - "%s: changing from interface %s to primary " + /* at this point, slave is the curr_active_slave */ + printk(KERN_INFO DRV_NAME + ": %s: changing from interface %s to primary " "interface %s\n", - master->name, - slave->dev->name, + bond_dev->name, + slave->dev->name, bond->primary_slave->dev->name); - + /* primary is up so switch to it */ - write_lock(&bond->ptrlock); - change_active_interface(bond, bond->primary_slave); - write_unlock(&bond->ptrlock); + write_lock(&bond->curr_slave_lock); + bond_change_active_slave(bond, bond->primary_slave); + write_unlock(&bond->curr_slave_lock); + slave = bond->primary_slave; slave->jiffies = jiffies; } else { @@ -2768,598 +2570,68 @@ /* the current slave must tx an arp to ensure backup slaves * rx traffic */ - if ((slave != NULL) && (my_ip != 0)) { - arp_send_all(slave); + if (slave && my_ip) { + bond_arp_send_all(bond, slave); } } - /* if we don't have a current_slave, search for the next available - * backup slave from the current_arp_slave and make it the candidate - * for becoming the current_slave + /* if we don't have a curr_active_slave, search for the next available + * backup slave from the current_arp_slave and make it the candidate + * for becoming the curr_active_slave */ - if (slave == NULL) { - - if ((bond->current_arp_slave == NULL) || - (bond->current_arp_slave == (slave_t *)bond)) { - bond->current_arp_slave = bond->prev; - } + if (!slave) { + if (!bond->current_arp_slave) { + bond->current_arp_slave = bond->first_slave; + } - if (bond->current_arp_slave != (slave_t *)bond) { + if (bond->current_arp_slave) { bond_set_slave_inactive_flags(bond->current_arp_slave); - slave = bond->current_arp_slave->next; /* search for next candidate */ - do { + bond_for_each_slave_from(bond, slave, i, bond->current_arp_slave) { if (IS_UP(slave->dev)) { slave->link = BOND_LINK_BACK; bond_set_slave_active_flags(slave); - arp_send_all(slave); + bond_arp_send_all(bond, slave); slave->jiffies = jiffies; bond->current_arp_slave = slave; break; } - /* if the link state is up at this point, we - * mark it down - this can happen if we have - * simultaneous link failures and - * reselect_active_interface doesn't make this - * one the current slave so it is still marked + /* if the link state is up at this point, we + * mark it down - this can happen if we have + * simultaneous link failures and + * reselect_active_interface doesn't make this + * one the current slave so it is still marked * up when it is actually down */ if (slave->link == BOND_LINK_UP) { slave->link = BOND_LINK_DOWN; - if (slave->link_failure_count < - UINT_MAX) { + if (slave->link_failure_count < UINT_MAX) { slave->link_failure_count++; } bond_set_slave_inactive_flags(slave); - printk(KERN_INFO - "%s: backup interface " - "%s is now down.\n", - master->name, - slave->dev->name); - } - } while ((slave = slave->next) != - bond->current_arp_slave->next); - } - } - - read_unlock(&bond->lock); - mod_timer(&bond->arp_timer, next_timer); -} - -static int bond_sethwaddr(struct net_device *master, struct net_device *slave) -{ -#ifdef BONDING_DEBUG - printk(KERN_CRIT "bond_sethwaddr: master=%x\n", (unsigned int)master); - printk(KERN_CRIT "bond_sethwaddr: slave=%x\n", (unsigned int)slave); - printk(KERN_CRIT "bond_sethwaddr: slave->addr_len=%d\n", slave->addr_len); -#endif - memcpy(master->dev_addr, slave->dev_addr, slave->addr_len); - return 0; -} - -static int bond_info_query(struct net_device *master, struct ifbond *info) -{ - bonding_t *bond = (struct bonding *) master->priv; - slave_t *slave; - - info->bond_mode = bond_mode; - info->num_slaves = 0; - info->miimon = miimon; - - read_lock_bh(&bond->lock); - for (slave = bond->prev; slave != (slave_t *)bond; slave = slave->prev) { - info->num_slaves++; - } - read_unlock_bh(&bond->lock); - - return 0; -} - -static int bond_slave_info_query(struct net_device *master, - struct ifslave *info) -{ - bonding_t *bond = (struct bonding *) master->priv; - slave_t *slave; - int cur_ndx = 0; - - if (info->slave_id < 0) { - return -ENODEV; - } - - read_lock_bh(&bond->lock); - for (slave = bond->prev; - slave != (slave_t *)bond && cur_ndx < info->slave_id; - slave = slave->prev) { - cur_ndx++; - } - read_unlock_bh(&bond->lock); - - if (slave != (slave_t *)bond) { - strcpy(info->slave_name, slave->dev->name); - info->link = slave->link; - info->state = slave->state; - info->link_failure_count = slave->link_failure_count; - } else { - return -ENODEV; - } - - return 0; -} - -static int bond_ethtool_ioctl(struct net_device *master_dev, struct ifreq *ifr) -{ - void *addr = ifr->ifr_data; - uint32_t cmd; - - if (get_user(cmd, (uint32_t *) addr)) - return -EFAULT; - - switch (cmd) { - - case ETHTOOL_GDRVINFO: - { - struct ethtool_drvinfo info; - char *endptr; - - if (copy_from_user(&info, addr, sizeof(info))) - return -EFAULT; - - if (strcmp(info.driver, "ifenslave") == 0) { - int new_abi_ver; - - new_abi_ver = simple_strtoul(info.fw_version, - &endptr, 0); - if (*endptr) { - printk(KERN_ERR - "bonding: Error: got invalid ABI" - " version from application\n"); - - return -EINVAL; - } - if (orig_app_abi_ver == -1) { - orig_app_abi_ver = new_abi_ver; + printk(KERN_INFO DRV_NAME + ": %s: backup interface %s is " + "now down.\n", + bond_dev->name, + slave->dev->name); } - - app_abi_ver = new_abi_ver; - } - - strncpy(info.driver, DRV_NAME, 32); - strncpy(info.version, DRV_VERSION, 32); - snprintf(info.fw_version, 32, "%d", BOND_ABI_VERSION); - - if (copy_to_user(addr, &info, sizeof(info))) - return -EFAULT; - - return 0; - } - break; - default: - return -EOPNOTSUPP; - } -} - -static int bond_ioctl(struct net_device *master_dev, struct ifreq *ifr, int cmd) -{ - struct net_device *slave_dev = NULL; - struct ifbond *u_binfo = NULL, k_binfo; - struct ifslave *u_sinfo = NULL, k_sinfo; - struct mii_ioctl_data *mii = NULL; - int prev_abi_ver = orig_app_abi_ver; - int ret = 0; - -#ifdef BONDING_DEBUG - printk(KERN_INFO "bond_ioctl: master=%s, cmd=%d\n", - master_dev->name, cmd); -#endif - - switch (cmd) { - case SIOCETHTOOL: - return bond_ethtool_ioctl(master_dev, ifr); - - case SIOCGMIIPHY: - mii = (struct mii_ioctl_data *)&ifr->ifr_data; - if (mii == NULL) { - return -EINVAL; - } - mii->phy_id = 0; - /* Fall Through */ - case SIOCGMIIREG: - /* - * We do this again just in case we were called by SIOCGMIIREG - * instead of SIOCGMIIPHY. - */ - mii = (struct mii_ioctl_data *)&ifr->ifr_data; - if (mii == NULL) { - return -EINVAL; - } - if (mii->reg_num == 1) { - mii->val_out = bond_check_mii_link( - (struct bonding *)master_dev->priv); - } - return 0; - case BOND_INFO_QUERY_OLD: - case SIOCBONDINFOQUERY: - u_binfo = (struct ifbond *)ifr->ifr_data; - if (copy_from_user(&k_binfo, u_binfo, sizeof(ifbond))) { - return -EFAULT; - } - ret = bond_info_query(master_dev, &k_binfo); - if (ret == 0) { - if (copy_to_user(u_binfo, &k_binfo, sizeof(ifbond))) { - return -EFAULT; - } - } - return ret; - case BOND_SLAVE_INFO_QUERY_OLD: - case SIOCBONDSLAVEINFOQUERY: - u_sinfo = (struct ifslave *)ifr->ifr_data; - if (copy_from_user(&k_sinfo, u_sinfo, sizeof(ifslave))) { - return -EFAULT; - } - ret = bond_slave_info_query(master_dev, &k_sinfo); - if (ret == 0) { - if (copy_to_user(u_sinfo, &k_sinfo, sizeof(ifslave))) { - return -EFAULT; - } - } - return ret; - } - - if (!capable(CAP_NET_ADMIN)) { - return -EPERM; - } - - if (orig_app_abi_ver == -1) { - /* no orig_app_abi_ver was provided yet, so we'll use the - * current one from now on, even if it's 0 - */ - orig_app_abi_ver = app_abi_ver; - - } else if (orig_app_abi_ver != app_abi_ver) { - printk(KERN_ERR - "bonding: Error: already using ifenslave ABI " - "version %d; to upgrade ifenslave to version %d, " - "you must first reload bonding.\n", - orig_app_abi_ver, app_abi_ver); - return -EINVAL; - } - - slave_dev = dev_get_by_name(ifr->ifr_slave); - -#ifdef BONDING_DEBUG - printk(KERN_INFO "slave_dev=%x: \n", (unsigned int)slave_dev); - printk(KERN_INFO "slave_dev->name=%s: \n", slave_dev->name); -#endif - - if (slave_dev == NULL) { - ret = -ENODEV; - } else { - switch (cmd) { - case BOND_ENSLAVE_OLD: - case SIOCBONDENSLAVE: - ret = bond_enslave(master_dev, slave_dev); - break; - case BOND_RELEASE_OLD: - case SIOCBONDRELEASE: - ret = bond_release(master_dev, slave_dev); - break; - case BOND_SETHWADDR_OLD: - case SIOCBONDSETHWADDR: - ret = bond_sethwaddr(master_dev, slave_dev); - break; - case BOND_CHANGE_ACTIVE_OLD: - case SIOCBONDCHANGEACTIVE: - if (USES_PRIMARY(bond_mode)) { - ret = bond_change_active(master_dev, slave_dev); - } - else { - ret = -EINVAL; } - break; - default: - ret = -EOPNOTSUPP; } - dev_put(slave_dev); } - if (ret < 0) { - /* The ioctl failed, so there's no point in changing the - * orig_app_abi_ver. We'll restore it's value just in case - * we've changed it earlier in this function. - */ - orig_app_abi_ver = prev_abi_ver; +re_arm: + if (bond->params.arp_interval) { + mod_timer(&bond->arp_timer, jiffies + delta_in_ticks); } - - return ret; -} - -#ifdef CONFIG_NET_FASTROUTE -static int bond_accept_fastpath(struct net_device *dev, struct dst_entry *dst) -{ - return -1; -} -#endif - -/* - * in broadcast mode, we send everything to all usable interfaces. - */ -static int bond_xmit_broadcast(struct sk_buff *skb, struct net_device *dev) -{ - slave_t *slave, *start_at; - struct bonding *bond = (struct bonding *) dev->priv; - struct net_device *device_we_should_send_to = 0; - - if (!IS_UP(dev)) { /* bond down */ - dev_kfree_skb(skb); - return 0; - } - - read_lock(&bond->lock); - - read_lock(&bond->ptrlock); - slave = start_at = bond->current_slave; - read_unlock(&bond->ptrlock); - - if (slave == NULL) { /* we're at the root, get the first slave */ - /* no suitable interface, frame not sent */ - read_unlock(&bond->lock); - dev_kfree_skb(skb); - return 0; - } - - do { - if (IS_UP(slave->dev) - && (slave->link == BOND_LINK_UP) - && (slave->state == BOND_STATE_ACTIVE)) { - if (device_we_should_send_to) { - struct sk_buff *skb2; - if ((skb2 = skb_clone(skb, GFP_ATOMIC)) == NULL) { - printk(KERN_ERR "bond_xmit_broadcast: skb_clone() failed\n"); - continue; - } - - skb2->dev = device_we_should_send_to; - skb2->priority = 1; - dev_queue_xmit(skb2); - } - device_we_should_send_to = slave->dev; - } - } while ((slave = slave->next) != start_at); - - if (device_we_should_send_to) { - skb->dev = device_we_should_send_to; - skb->priority = 1; - dev_queue_xmit(skb); - } else - dev_kfree_skb(skb); - - /* frame sent to all suitable interfaces */ - read_unlock(&bond->lock); - return 0; -} - -static int bond_xmit_roundrobin(struct sk_buff *skb, struct net_device *dev) -{ - slave_t *slave, *start_at; - struct bonding *bond = (struct bonding *) dev->priv; - - if (!IS_UP(dev)) { /* bond down */ - dev_kfree_skb(skb); - return 0; - } - - read_lock(&bond->lock); - - read_lock(&bond->ptrlock); - slave = start_at = bond->current_slave; - read_unlock(&bond->ptrlock); - - if (slave == NULL) { /* we're at the root, get the first slave */ - /* no suitable interface, frame not sent */ - dev_kfree_skb(skb); - read_unlock(&bond->lock); - return 0; - } - - do { - if (IS_UP(slave->dev) - && (slave->link == BOND_LINK_UP) - && (slave->state == BOND_STATE_ACTIVE)) { - - skb->dev = slave->dev; - skb->priority = 1; - dev_queue_xmit(skb); - - write_lock(&bond->ptrlock); - bond->current_slave = slave->next; - write_unlock(&bond->ptrlock); - - read_unlock(&bond->lock); - return 0; - } - } while ((slave = slave->next) != start_at); - - /* no suitable interface, frame not sent */ - dev_kfree_skb(skb); - read_unlock(&bond->lock); - return 0; -} - -/* - * in XOR mode, we determine the output device by performing xor on - * the source and destination hw adresses. If this device is not - * enabled, find the next slave following this xor slave. - */ -static int bond_xmit_xor(struct sk_buff *skb, struct net_device *dev) -{ - slave_t *slave, *start_at; - struct bonding *bond = (struct bonding *) dev->priv; - struct ethhdr *data = (struct ethhdr *)skb->data; - int slave_no; - - if (!IS_UP(dev)) { /* bond down */ - dev_kfree_skb(skb); - return 0; - } - - read_lock(&bond->lock); - slave = bond->prev; - - /* we're at the root, get the first slave */ - if (bond->slave_cnt == 0) { - /* no suitable interface, frame not sent */ - dev_kfree_skb(skb); - read_unlock(&bond->lock); - return 0; - } - - slave_no = (data->h_dest[5]^slave->dev->dev_addr[5]) % bond->slave_cnt; - - while ( (slave_no > 0) && (slave != (slave_t *)bond) ) { - slave = slave->prev; - slave_no--; - } - start_at = slave; - - do { - if (IS_UP(slave->dev) - && (slave->link == BOND_LINK_UP) - && (slave->state == BOND_STATE_ACTIVE)) { - - skb->dev = slave->dev; - skb->priority = 1; - dev_queue_xmit(skb); - - read_unlock(&bond->lock); - return 0; - } - } while ((slave = slave->next) != start_at); - - /* no suitable interface, frame not sent */ - dev_kfree_skb(skb); - read_unlock(&bond->lock); - return 0; -} - -/* - * in active-backup mode, we know that bond->current_slave is always valid if - * the bond has a usable interface. - */ -static int bond_xmit_activebackup(struct sk_buff *skb, struct net_device *dev) -{ - struct bonding *bond = (struct bonding *) dev->priv; - int ret; - - if (!IS_UP(dev)) { /* bond down */ - dev_kfree_skb(skb); - return 0; - } - - /* if we are sending arp packets, try to at least - identify our own ip address */ - if ( (arp_interval > 0) && (my_ip == 0) && - (skb->protocol == __constant_htons(ETH_P_ARP) ) ) { - char *the_ip = (((char *)skb->data)) - + sizeof(struct ethhdr) - + sizeof(struct arphdr) + - ETH_ALEN; - memcpy(&my_ip, the_ip, 4); - } - - /* if we are sending arp packets and don't know - * the target hw address, save it so we don't need - * to use a broadcast address. - * don't do this if in active backup mode because the slaves must - * receive packets to stay up, and the only ones they receive are - * broadcasts. - */ - if ( (bond_mode != BOND_MODE_ACTIVEBACKUP) && - (arp_ip_count == 1) && - (arp_interval > 0) && (arp_target_hw_addr == NULL) && - (skb->protocol == __constant_htons(ETH_P_IP) ) ) { - struct ethhdr *eth_hdr = - (struct ethhdr *) (((char *)skb->data)); - struct iphdr *ip_hdr = (struct iphdr *)(eth_hdr + 1); - - if (arp_target[0] == ip_hdr->daddr) { - arp_target_hw_addr = kmalloc(ETH_ALEN, GFP_KERNEL); - if (arp_target_hw_addr != NULL) - memcpy(arp_target_hw_addr, eth_hdr->h_dest, ETH_ALEN); - } - } - - read_lock(&bond->lock); - - read_lock(&bond->ptrlock); - if (bond->current_slave != NULL) { /* one usable interface */ - skb->dev = bond->current_slave->dev; - read_unlock(&bond->ptrlock); - skb->priority = 1; - ret = dev_queue_xmit(skb); - read_unlock(&bond->lock); - return 0; - } - else { - read_unlock(&bond->ptrlock); - } - - /* no suitable interface, frame not sent */ -#ifdef BONDING_DEBUG - printk(KERN_INFO "There was no suitable interface, so we don't transmit\n"); -#endif - dev_kfree_skb(skb); +out: read_unlock(&bond->lock); - return 0; } -static struct net_device_stats *bond_get_stats(struct net_device *dev) -{ - bonding_t *bond = dev->priv; - struct net_device_stats *stats = &(bond->stats), *sstats; - slave_t *slave; - - memset(stats, 0, sizeof(struct net_device_stats)); - - read_lock_bh(&bond->lock); - - for (slave = bond->prev; slave != (slave_t *)bond; slave = slave->prev) { - sstats = slave->dev->get_stats(slave->dev); - - stats->rx_packets += sstats->rx_packets; - stats->rx_bytes += sstats->rx_bytes; - stats->rx_errors += sstats->rx_errors; - stats->rx_dropped += sstats->rx_dropped; - - stats->tx_packets += sstats->tx_packets; - stats->tx_bytes += sstats->tx_bytes; - stats->tx_errors += sstats->tx_errors; - stats->tx_dropped += sstats->tx_dropped; - - stats->multicast += sstats->multicast; - stats->collisions += sstats->collisions; - - stats->rx_length_errors += sstats->rx_length_errors; - stats->rx_over_errors += sstats->rx_over_errors; - stats->rx_crc_errors += sstats->rx_crc_errors; - stats->rx_frame_errors += sstats->rx_frame_errors; - stats->rx_fifo_errors += sstats->rx_fifo_errors; - stats->rx_missed_errors += sstats->rx_missed_errors; - - stats->tx_aborted_errors += sstats->tx_aborted_errors; - stats->tx_carrier_errors += sstats->tx_carrier_errors; - stats->tx_fifo_errors += sstats->tx_fifo_errors; - stats->tx_heartbeat_errors += sstats->tx_heartbeat_errors; - stats->tx_window_errors += sstats->tx_window_errors; - - } - - read_unlock_bh(&bond->lock); - return stats; -} +/*------------------------------ proc/seq_file-------------------------------*/ #ifdef CONFIG_PROC_FS @@ -3370,6 +2642,7 @@ struct bonding *bond = seq->private; loff_t off = 0; struct slave *slave; + int i; /* make sure the bond won't be taken away */ read_lock(&dev_base_lock); @@ -3379,9 +2652,7 @@ return SEQ_START_TOKEN; } - for (slave = bond->prev; slave != (slave_t *)bond; - slave = slave->prev) { - + bond_for_each_slave(bond, slave, i) { if (++off == *pos) { return slave; } @@ -3397,12 +2668,12 @@ ++*pos; if (v == SEQ_START_TOKEN) { - slave = bond->prev; - } else { - slave = slave->prev; + return bond->first_slave; } - return (slave == (struct slave *) bond) ? NULL : slave; + slave = slave->next; + + return (slave == bond->first_slave) ? NULL : slave; } static void bond_info_seq_stop(struct seq_file *seq, void *v) @@ -3413,38 +2684,44 @@ read_unlock(&dev_base_lock); } -static void bond_info_show_master(struct seq_file *seq, struct bonding *bond) +static void bond_info_show_master(struct seq_file *seq) { + struct bonding *bond = seq->private; struct slave *curr; - read_lock(&bond->ptrlock); - curr = bond->current_slave; - read_unlock(&bond->ptrlock); - - seq_printf(seq, "Bonding Mode: %s\n", bond_mode_name()); - - if (USES_PRIMARY(bond_mode)) { - if (curr) { - seq_printf(seq, - "Currently Active Slave: %s\n", - curr->dev->name); - } + read_lock(&bond->curr_slave_lock); + curr = bond->curr_active_slave; + read_unlock(&bond->curr_slave_lock); + + seq_printf(seq, "Bonding Mode: %s\n", + bond_mode_name(bond->params.mode)); + + if (USES_PRIMARY(bond->params.mode)) { + seq_printf(seq, "Primary Slave: %s\n", + (bond->params.primary[0]) ? + bond->params.primary : "None"); + + seq_printf(seq, "Currently Active Slave: %s\n", + (curr) ? curr->dev->name : "None"); } seq_printf(seq, "MII Status: %s\n", (curr) ? "up" : "down"); - seq_printf(seq, "MII Polling Interval (ms): %d\n", miimon); - seq_printf(seq, "Up Delay (ms): %d\n", updelay * miimon); - seq_printf(seq, "Down Delay (ms): %d\n", downdelay * miimon); - seq_printf(seq, "Multicast Mode: %s\n", multicast_mode_name()); + seq_printf(seq, "MII Polling Interval (ms): %d\n", bond->params.miimon); + seq_printf(seq, "Up Delay (ms): %d\n", + bond->params.updelay * bond->params.miimon); + seq_printf(seq, "Down Delay (ms): %d\n", + bond->params.downdelay * bond->params.miimon); - if (bond_mode == BOND_MODE_8023AD) { + if (bond->params.mode == BOND_MODE_8023AD) { struct ad_info ad_info; seq_puts(seq, "\n802.3ad info\n"); + seq_printf(seq, "LACP rate: %s\n", + (bond->params.lacp_fast) ? "fast" : "slow"); if (bond_3ad_get_active_agg_info(bond, &ad_info)) { seq_printf(seq, "bond %s has no active aggregator\n", - bond->device->name); + bond->dev->name); } else { seq_printf(seq, "Active Aggregator Info:\n"); @@ -3469,6 +2746,8 @@ static void bond_info_show_slave(struct seq_file *seq, const struct slave *slave) { + struct bonding *bond = seq->private; + seq_printf(seq, "\nSlave Interface: %s\n", slave->dev->name); seq_printf(seq, "MII Status: %s\n", (slave->link == BOND_LINK_UP) ? "up" : "down"); @@ -3486,7 +2765,7 @@ slave->perm_hwaddr[5]); } - if (bond_mode == BOND_MODE_8023AD) { + if (bond->params.mode == BOND_MODE_8023AD) { const struct aggregator *agg = SLAVE_AD_INFO(slave).port.aggregator; @@ -3503,7 +2782,7 @@ { if (v == SEQ_START_TOKEN) { seq_printf(seq, "%s\n", version); - bond_info_show_master(seq, seq->private); + bond_info_show_master(seq); } else { bond_info_show_slave(seq, v); } @@ -3522,55 +2801,56 @@ { struct seq_file *seq; struct proc_dir_entry *proc; - int rc; + int res; - rc = seq_open(file, &bond_info_seq_ops); - if (!rc) { + res = seq_open(file, &bond_info_seq_ops); + if (!res) { /* recover the pointer buried in proc_dir_entry data */ seq = file->private_data; proc = PDE(inode); seq->private = proc->data; } - return rc; + + return res; } static struct file_operations bond_info_fops = { - .owner = THIS_MODULE, + .owner = THIS_MODULE, .open = bond_info_open, .read = seq_read, .llseek = seq_lseek, .release = seq_release, }; -static int bond_create_proc_info(struct bonding *bond) +static int bond_create_proc_entry(struct bonding *bond) { - struct net_device *dev = bond->device; + struct net_device *bond_dev = bond->dev; if (bond_proc_dir) { - bond->bond_proc_file = create_proc_entry(dev->name, - S_IRUGO, - bond_proc_dir); - if (bond->bond_proc_file == NULL) { - printk(KERN_WARNING - "%s: Cannot create /proc/net/bonding/%s\n", - dev->name, dev->name); + bond->proc_entry = create_proc_entry(bond_dev->name, + S_IRUGO, + bond_proc_dir); + if (bond->proc_entry == NULL) { + printk(KERN_WARNING DRV_NAME + ": Warning: Cannot create /proc/net/%s/%s\n", + DRV_NAME, bond_dev->name); } else { - bond->bond_proc_file->data = bond; - bond->bond_proc_file->proc_fops = &bond_info_fops; - bond->bond_proc_file->owner = THIS_MODULE; - memcpy(bond->procdir_name, dev->name, IFNAMSIZ); + bond->proc_entry->data = bond; + bond->proc_entry->proc_fops = &bond_info_fops; + bond->proc_entry->owner = THIS_MODULE; + memcpy(bond->proc_file_name, bond_dev->name, IFNAMSIZ); } } return 0; } -static void bond_destroy_proc_info(struct bonding *bond) +static void bond_remove_proc_entry(struct bonding *bond) { - if (bond_proc_dir && bond->bond_proc_file) { - remove_proc_entry(bond->procdir_name, bond_proc_dir); - memset(bond->procdir_name, 0, IFNAMSIZ); - bond->bond_proc_file = NULL; + if (bond_proc_dir && bond->proc_entry) { + remove_proc_entry(bond->proc_file_name, bond_proc_dir); + memset(bond->proc_file_name, 0, IFNAMSIZ); + bond->proc_entry = NULL; } } @@ -3631,158 +2911,24 @@ } #endif /* CONFIG_PROC_FS */ -/* - * Change HW address - * - * Note that many devices must be down to change the HW address, and - * downing the master releases all slaves. We can make bonds full of - * bonding devices to test this, however. - */ -static inline int -bond_set_mac_address(struct net_device *dev, void *addr) -{ - struct bonding *bond = dev->priv; - struct sockaddr *sa = addr, tmp_sa; - struct slave *slave; - int error; - - dprintk(KERN_INFO "bond_set_mac_address %p %s\n", dev, - dev->name); - - if (!is_valid_ether_addr(sa->sa_data)) { - return -EADDRNOTAVAIL; - } - - for (slave = bond->prev; slave != (struct slave *)bond; - slave = slave->prev) { - dprintk(KERN_INFO "bond_set_mac: slave %p %s\n", slave, - slave->dev->name); - if (slave->dev->set_mac_address == NULL) { - error = -EOPNOTSUPP; - dprintk(KERN_INFO "bond_set_mac EOPNOTSUPP %s\n", - slave->dev->name); - goto unwind; - } - - error = slave->dev->set_mac_address(slave->dev, addr); - if (error) { - /* TODO: consider downing the slave - * and retry ? - * User should expect communications - * breakage anyway until ARP finish - * updating, so... - */ - dprintk(KERN_INFO "bond_set_mac err %d %s\n", - error, slave->dev->name); - goto unwind; - } - } - - /* success */ - memcpy(dev->dev_addr, sa->sa_data, dev->addr_len); - return 0; - -unwind: - memcpy(tmp_sa.sa_data, dev->dev_addr, dev->addr_len); - tmp_sa.sa_family = dev->type; - - for (slave = slave->next; slave != bond->next; - slave = slave->next) { - int tmp_error; - - tmp_error = slave->dev->set_mac_address(slave->dev, &tmp_sa); - if (tmp_error) { - dprintk(KERN_INFO "bond_set_mac_address: " - "unwind err %d dev %s\n", - tmp_error, slave->dev->name); - } - } - - return error; -} - -/* - * Change the MTU of all of a master's slaves to match the master - */ -static inline int -bond_change_mtu(struct net_device *dev, int newmtu) -{ - bonding_t *bond = dev->priv; - slave_t *slave; - int error; - - dprintk(KERN_INFO "CM: b %p nm %d\n", bond, newmtu); - for (slave = bond->prev; slave != (slave_t *)bond; - slave = slave->prev) { - dprintk(KERN_INFO "CM: s %p s->p %p c_m %p\n", slave, - slave->prev, slave->dev->change_mtu); - if (slave->dev->change_mtu) { - error = slave->dev->change_mtu(slave->dev, newmtu); - } else { - slave->dev->mtu = newmtu; - error = 0; - } - - if (error) { - /* If we failed to set the slave's mtu to the new value - * we must abort the operation even in ACTIVE_BACKUP - * mode, because if we allow the backup slaves to have - * different mtu values than the active slave we'll - * need to change their mtu when doing a failover. That - * means changing their mtu from timer context, which - * is probably not a good idea. - */ - dprintk(KERN_INFO "bond_change_mtu err %d %s\n", - error, slave->dev->name); - goto unwind; - } - } - - dev->mtu = newmtu; - return 0; - - -unwind: - for (slave = slave->next; slave != bond->next; - slave = slave->next) { - - if (slave->dev->change_mtu) { - slave->dev->change_mtu(slave->dev, dev->mtu); - } else { - slave->dev->mtu = dev->mtu; - } - } - - return error; -} +/*-------------------------- netdev event handling --------------------------*/ /* * Change device name */ -static inline int bond_event_changename(struct bonding *bond) +static int bond_event_changename(struct bonding *bond) { #ifdef CONFIG_PROC_FS - bond_destroy_proc_info(bond); - bond_create_proc_info(bond); + bond_remove_proc_entry(bond); + bond_create_proc_entry(bond); #endif return NOTIFY_DONE; } -static int bond_master_netdev_event(unsigned long event, struct net_device *event_dev) +static int bond_master_netdev_event(unsigned long event, struct net_device *bond_dev) { - struct bonding *bond, *event_bond = NULL; - - list_for_each_entry(bond, &bond_dev_list, bond_list) { - if (bond == event_dev->priv) { - event_bond = bond; - break; - } - } - - if (event_bond == NULL) { - return NOTIFY_DONE; - } + struct bonding *event_bond = bond_dev->priv; switch (event) { case NETDEV_CHANGENAME: @@ -3799,14 +2945,14 @@ return NOTIFY_DONE; } -static int bond_slave_netdev_event(unsigned long event, struct net_device *event_dev) +static int bond_slave_netdev_event(unsigned long event, struct net_device *slave_dev) { - struct net_device *master = event_dev->master; + struct net_device *bond_dev = slave_dev->master; switch (event) { case NETDEV_UNREGISTER: - if (master != NULL) { - bond_release(master, event_dev); + if (bond_dev) { + bond_release(bond_dev, slave_dev); } break; case NETDEV_CHANGE: @@ -3858,184 +3004,918 @@ static int bond_netdev_event(struct notifier_block *this, unsigned long event, void *ptr) { struct net_device *event_dev = (struct net_device *)ptr; - unsigned short flags; - int res = NOTIFY_DONE; - dprintk(KERN_INFO "bond_netdev_event n_b %p ev %lx ptr %p\n", - this, event, ptr); + dprintk("event_dev: %s, event: %lx\n", + (event_dev ? event_dev->name : "None"), + event); + + if (event_dev->flags & IFF_MASTER) { + dprintk("IFF_MASTER\n"); + return bond_master_netdev_event(event, event_dev); + } + + if (event_dev->flags & IFF_SLAVE) { + dprintk("IFF_SLAVE\n"); + return bond_slave_netdev_event(event, event_dev); + } + + return NOTIFY_DONE; +} + +static struct notifier_block bond_netdev_notifier = { + .notifier_call = bond_netdev_event, +}; + +/*-------------------------- Packet type handling ---------------------------*/ + +/* register to receive lacpdus on a bond */ +static void bond_register_lacpdu(struct bonding *bond) +{ + struct packet_type *pk_type = &(BOND_AD_INFO(bond).ad_pkt_type); + + /* initialize packet type */ + pk_type->type = PKT_TYPE_LACPDU; + pk_type->dev = bond->dev; + pk_type->func = bond_3ad_lacpdu_recv; + + dev_add_pack(pk_type); +} + +/* unregister to receive lacpdus on a bond */ +static void bond_unregister_lacpdu(struct bonding *bond) +{ + dev_remove_pack(&(BOND_AD_INFO(bond).ad_pkt_type)); +} + +/*-------------------------- Device entry points ----------------------------*/ + +static int bond_open(struct net_device *bond_dev) +{ + struct bonding *bond = bond_dev->priv; + struct timer_list *mii_timer = &bond->mii_timer; + struct timer_list *arp_timer = &bond->arp_timer; + + bond->kill_timers = 0; - flags = event_dev->flags & (IFF_MASTER | IFF_SLAVE); - switch (flags) { - case IFF_MASTER: - res = bond_master_netdev_event(event, event_dev); + if ((bond->params.mode == BOND_MODE_TLB) || + (bond->params.mode == BOND_MODE_ALB)) { + struct timer_list *alb_timer = &(BOND_ALB_INFO(bond).alb_timer); + + /* bond_alb_initialize must be called before the timer + * is started. + */ + if (bond_alb_initialize(bond, (bond->params.mode == BOND_MODE_ALB))) { + /* something went wrong - fail the open operation */ + return -1; + } + + init_timer(alb_timer); + alb_timer->expires = jiffies + 1; + alb_timer->data = (unsigned long)bond; + alb_timer->function = (void *)&bond_alb_monitor; + add_timer(alb_timer); + } + + if (bond->params.miimon) { /* link check interval, in milliseconds. */ + init_timer(mii_timer); + mii_timer->expires = jiffies + 1; + mii_timer->data = (unsigned long)bond_dev; + mii_timer->function = (void *)&bond_mii_monitor; + add_timer(mii_timer); + } + + if (bond->params.arp_interval) { /* arp interval, in milliseconds. */ + init_timer(arp_timer); + arp_timer->expires = jiffies + 1; + arp_timer->data = (unsigned long)bond_dev; + if (bond->params.mode == BOND_MODE_ACTIVEBACKUP) { + arp_timer->function = (void *)&bond_activebackup_arp_mon; + } else { + arp_timer->function = (void *)&bond_loadbalance_arp_mon; + } + add_timer(arp_timer); + } + + if (bond->params.mode == BOND_MODE_8023AD) { + struct timer_list *ad_timer = &(BOND_AD_INFO(bond).ad_timer); + init_timer(ad_timer); + ad_timer->expires = jiffies + 1; + ad_timer->data = (unsigned long)bond; + ad_timer->function = (void *)&bond_3ad_state_machine_handler; + add_timer(ad_timer); + + /* register to receive LACPDUs */ + bond_register_lacpdu(bond); + } + + return 0; +} + +static int bond_close(struct net_device *bond_dev) +{ + struct bonding *bond = bond_dev->priv; + + write_lock_bh(&bond->lock); + + bond_mc_list_destroy(bond); + + if (bond->params.mode == BOND_MODE_8023AD) { + /* Unregister the receive of LACPDUs */ + bond_unregister_lacpdu(bond); + } + + /* signal timers not to re-arm */ + bond->kill_timers = 1; + + write_unlock_bh(&bond->lock); + + /* del_timer_sync must run without holding the bond->lock + * because a running timer might be trying to hold it too + */ + + if (bond->params.miimon) { /* link check interval, in milliseconds. */ + del_timer_sync(&bond->mii_timer); + } + + if (bond->params.arp_interval) { /* arp interval, in milliseconds. */ + del_timer_sync(&bond->arp_timer); + } + + switch (bond->params.mode) { + case BOND_MODE_8023AD: + del_timer_sync(&(BOND_AD_INFO(bond).ad_timer)); break; - case IFF_SLAVE: - res = bond_slave_netdev_event(event, event_dev); + case BOND_MODE_TLB: + case BOND_MODE_ALB: + del_timer_sync(&(BOND_ALB_INFO(bond).alb_timer)); + break; + default: break; + } + + /* Release the bonded slaves */ + bond_release_all(bond_dev); + + if ((bond->params.mode == BOND_MODE_TLB) || + (bond->params.mode == BOND_MODE_ALB)) { + /* Must be called only after all + * slaves have been released + */ + bond_alb_deinitialize(bond); + } + + return 0; +} + +static struct net_device_stats *bond_get_stats(struct net_device *bond_dev) +{ + struct bonding *bond = bond_dev->priv; + struct net_device_stats *stats = &(bond->stats), *sstats; + struct slave *slave; + int i; + + memset(stats, 0, sizeof(struct net_device_stats)); + + read_lock_bh(&bond->lock); + + bond_for_each_slave(bond, slave, i) { + sstats = slave->dev->get_stats(slave->dev); + + stats->rx_packets += sstats->rx_packets; + stats->rx_bytes += sstats->rx_bytes; + stats->rx_errors += sstats->rx_errors; + stats->rx_dropped += sstats->rx_dropped; + + stats->tx_packets += sstats->tx_packets; + stats->tx_bytes += sstats->tx_bytes; + stats->tx_errors += sstats->tx_errors; + stats->tx_dropped += sstats->tx_dropped; + + stats->multicast += sstats->multicast; + stats->collisions += sstats->collisions; + + stats->rx_length_errors += sstats->rx_length_errors; + stats->rx_over_errors += sstats->rx_over_errors; + stats->rx_crc_errors += sstats->rx_crc_errors; + stats->rx_frame_errors += sstats->rx_frame_errors; + stats->rx_fifo_errors += sstats->rx_fifo_errors; + stats->rx_missed_errors += sstats->rx_missed_errors; + + stats->tx_aborted_errors += sstats->tx_aborted_errors; + stats->tx_carrier_errors += sstats->tx_carrier_errors; + stats->tx_fifo_errors += sstats->tx_fifo_errors; + stats->tx_heartbeat_errors += sstats->tx_heartbeat_errors; + stats->tx_window_errors += sstats->tx_window_errors; + } + + read_unlock_bh(&bond->lock); + + return stats; +} + +static int bond_do_ioctl(struct net_device *bond_dev, struct ifreq *ifr, int cmd) +{ + struct net_device *slave_dev = NULL; + struct ifbond *u_binfo = NULL, k_binfo; + struct ifslave *u_sinfo = NULL, k_sinfo; + struct mii_ioctl_data *mii = NULL; + int prev_abi_ver = orig_app_abi_ver; + int res = 0; + + dprintk("bond_ioctl: master=%s, cmd=%d\n", + bond_dev->name, cmd); + + switch (cmd) { + case SIOCETHTOOL: + return bond_ethtool_ioctl(bond_dev, ifr); + case SIOCGMIIPHY: + mii = (struct mii_ioctl_data *)&ifr->ifr_data; + if (!mii) { + return -EINVAL; + } + mii->phy_id = 0; + /* Fall Through */ + case SIOCGMIIREG: + /* + * We do this again just in case we were called by SIOCGMIIREG + * instead of SIOCGMIIPHY. + */ + mii = (struct mii_ioctl_data *)&ifr->ifr_data; + if (!mii) { + return -EINVAL; + } + + if (mii->reg_num == 1) { + struct bonding *bond = bond_dev->priv; + mii->val_out = 0; + read_lock_bh(&bond->lock); + read_lock(&bond->curr_slave_lock); + if (bond->curr_active_slave) { + mii->val_out = BMSR_LSTATUS; + } + read_unlock(&bond->curr_slave_lock); + read_unlock_bh(&bond->lock); + } + + return 0; + case BOND_INFO_QUERY_OLD: + case SIOCBONDINFOQUERY: + u_binfo = (struct ifbond *)ifr->ifr_data; + + if (copy_from_user(&k_binfo, u_binfo, sizeof(ifbond))) { + return -EFAULT; + } + + res = bond_info_query(bond_dev, &k_binfo); + if (res == 0) { + if (copy_to_user(u_binfo, &k_binfo, sizeof(ifbond))) { + return -EFAULT; + } + } + + return res; + case BOND_SLAVE_INFO_QUERY_OLD: + case SIOCBONDSLAVEINFOQUERY: + u_sinfo = (struct ifslave *)ifr->ifr_data; + + if (copy_from_user(&k_sinfo, u_sinfo, sizeof(ifslave))) { + return -EFAULT; + } + + res = bond_slave_info_query(bond_dev, &k_sinfo); + if (res == 0) { + if (copy_to_user(u_sinfo, &k_sinfo, sizeof(ifslave))) { + return -EFAULT; + } + } + + return res; default: - /* A master that is also a slave ? */ + /* Go on */ break; } + if (!capable(CAP_NET_ADMIN)) { + return -EPERM; + } + + if (orig_app_abi_ver == -1) { + /* no orig_app_abi_ver was provided yet, so we'll use the + * current one from now on, even if it's 0 + */ + orig_app_abi_ver = app_abi_ver; + + } else if (orig_app_abi_ver != app_abi_ver) { + printk(KERN_ERR DRV_NAME + ": Error: already using ifenslave ABI version %d; to " + "upgrade ifenslave to version %d, you must first " + "reload bonding.\n", + orig_app_abi_ver, app_abi_ver); + return -EINVAL; + } + + slave_dev = dev_get_by_name(ifr->ifr_slave); + + dprintk("slave_dev=%p: \n", slave_dev); + + if (!slave_dev) { + res = -ENODEV; + } else { + dprintk("slave_dev->name=%s: \n", slave_dev->name); + switch (cmd) { + case BOND_ENSLAVE_OLD: + case SIOCBONDENSLAVE: + res = bond_enslave(bond_dev, slave_dev); + break; + case BOND_RELEASE_OLD: + case SIOCBONDRELEASE: + res = bond_release(bond_dev, slave_dev); + break; + case BOND_SETHWADDR_OLD: + case SIOCBONDSETHWADDR: + res = bond_sethwaddr(bond_dev, slave_dev); + break; + case BOND_CHANGE_ACTIVE_OLD: + case SIOCBONDCHANGEACTIVE: + res = bond_ioctl_change_active(bond_dev, slave_dev); + break; + default: + res = -EOPNOTSUPP; + } + + dev_put(slave_dev); + } + + if (res < 0) { + /* The ioctl failed, so there's no point in changing the + * orig_app_abi_ver. We'll restore it's value just in case + * we've changed it earlier in this function. + */ + orig_app_abi_ver = prev_abi_ver; + } + return res; } -static struct notifier_block bond_netdev_notifier = { - .notifier_call = bond_netdev_event, -}; +static void bond_set_multicast_list(struct net_device *bond_dev) +{ + struct bonding *bond = bond_dev->priv; + struct dev_mc_list *dmi; -/* De-initialize device specific data. - * Caller must hold rtnl_lock. + write_lock_bh(&bond->lock); + + /* + * Do promisc before checking multicast_mode + */ + if ((bond_dev->flags & IFF_PROMISC) && !(bond->flags & IFF_PROMISC)) { + bond_set_promiscuity(bond, 1); + } + + if (!(bond_dev->flags & IFF_PROMISC) && (bond->flags & IFF_PROMISC)) { + bond_set_promiscuity(bond, -1); + } + + /* set allmulti flag to slaves */ + if ((bond_dev->flags & IFF_ALLMULTI) && !(bond->flags & IFF_ALLMULTI)) { + bond_set_allmulti(bond, 1); + } + + if (!(bond_dev->flags & IFF_ALLMULTI) && (bond->flags & IFF_ALLMULTI)) { + bond_set_allmulti(bond, -1); + } + + bond->flags = bond_dev->flags; + + /* looking for addresses to add to slaves' mc list */ + for (dmi = bond_dev->mc_list; dmi; dmi = dmi->next) { + if (!bond_mc_list_find_dmi(dmi, bond->mc_list)) { + bond_mc_add(bond, dmi->dmi_addr, dmi->dmi_addrlen); + } + } + + /* looking for addresses to delete from slaves' list */ + for (dmi = bond->mc_list; dmi; dmi = dmi->next) { + if (!bond_mc_list_find_dmi(dmi, bond_dev->mc_list)) { + bond_mc_delete(bond, dmi->dmi_addr, dmi->dmi_addrlen); + } + } + + /* save master's multicast list */ + bond_mc_list_destroy(bond); + bond_mc_list_copy(bond_dev->mc_list, bond, GFP_ATOMIC); + + write_unlock_bh(&bond->lock); +} + +/* + * Change the MTU of all of a master's slaves to match the master */ -static inline void bond_deinit(struct net_device *dev) +static int bond_change_mtu(struct net_device *bond_dev, int new_mtu) { - struct bonding *bond = dev->priv; + struct bonding *bond = bond_dev->priv; + struct slave *slave, *stop_at; + int res = 0; + int i; - list_del(&bond->bond_list); + dprintk("bond=%p, name=%s, new_mtu=%d\n", bond, + (bond_dev ? bond_dev->name : "None"), new_mtu); -#ifdef CONFIG_PROC_FS - bond_destroy_proc_info(bond); -#endif + /* Can't hold bond->lock with bh disabled here since + * some base drivers panic. On the other hand we can't + * hold bond->lock without bh disabled because we'll + * deadlock. The only solution is to rely on the fact + * that we're under rtnl_lock here, and the slaves + * list won't change. This doesn't solve the problem + * of setting the slave's MTU while it is + * transmitting, but the assumption is that the base + * driver can handle that. + * + * TODO: figure out a way to safely iterate the slaves + * list, but without holding a lock around the actual + * call to the base driver. + */ + + bond_for_each_slave(bond, slave, i) { + dprintk("s %p s->p %p c_m %p\n", slave, + slave->prev, slave->dev->change_mtu); + if (slave->dev->change_mtu) { + res = slave->dev->change_mtu(slave->dev, new_mtu); + } else { + slave->dev->mtu = new_mtu; + res = 0; + } + + if (res) { + /* If we failed to set the slave's mtu to the new value + * we must abort the operation even in ACTIVE_BACKUP + * mode, because if we allow the backup slaves to have + * different mtu values than the active slave we'll + * need to change their mtu when doing a failover. That + * means changing their mtu from timer context, which + * is probably not a good idea. + */ + dprintk("err %d %s\n", res, slave->dev->name); + goto unwind; + } + } + + bond_dev->mtu = new_mtu; + + return 0; + +unwind: + /* unwind from head to the slave that failed */ + stop_at = slave; + bond_for_each_slave_from_to(bond, slave, i, bond->first_slave, stop_at) { + int tmp_res; + + if (slave->dev->change_mtu) { + tmp_res = slave->dev->change_mtu(slave->dev, bond_dev->mtu); + if (tmp_res) { + dprintk("unwind err %d dev %s\n", tmp_res, + slave->dev->name); + } + } else { + slave->dev->mtu = bond_dev->mtu; + } + } + + return res; } -/* Unregister and free all bond devices. - * Caller must hold rtnl_lock. +/* + * Change HW address + * + * Note that many devices must be down to change the HW address, and + * downing the master releases all slaves. We can make bonds full of + * bonding devices to test this, however. */ -static void bond_free_all(void) +static int bond_set_mac_address(struct net_device *bond_dev, void *addr) { - struct bonding *bond, *nxt; + struct bonding *bond = bond_dev->priv; + struct sockaddr *sa = addr, tmp_sa; + struct slave *slave, *stop_at; + int res = 0; + int i; - list_for_each_entry_safe(bond, nxt, &bond_dev_list, bond_list) { - struct net_device *dev = bond->device; + dprintk("bond=%p, name=%s\n", bond, (bond_dev ? bond_dev->name : "None")); - unregister_netdevice(dev); - bond_deinit(dev); + if (!is_valid_ether_addr(sa->sa_data)) { + return -EADDRNOTAVAIL; } -#ifdef CONFIG_PROC_FS - bond_destroy_proc_dir(); -#endif + /* Can't hold bond->lock with bh disabled here since + * some base drivers panic. On the other hand we can't + * hold bond->lock without bh disabled because we'll + * deadlock. The only solution is to rely on the fact + * that we're under rtnl_lock here, and the slaves + * list won't change. This doesn't solve the problem + * of setting the slave's hw address while it is + * transmitting, but the assumption is that the base + * driver can handle that. + * + * TODO: figure out a way to safely iterate the slaves + * list, but without holding a lock around the actual + * call to the base driver. + */ + + bond_for_each_slave(bond, slave, i) { + dprintk("slave %p %s\n", slave, slave->dev->name); + + if (slave->dev->set_mac_address == NULL) { + res = -EOPNOTSUPP; + dprintk("EOPNOTSUPP %s\n", slave->dev->name); + goto unwind; + } + + res = slave->dev->set_mac_address(slave->dev, addr); + if (res) { + /* TODO: consider downing the slave + * and retry ? + * User should expect communications + * breakage anyway until ARP finish + * updating, so... + */ + dprintk("err %d %s\n", res, slave->dev->name); + goto unwind; + } + } + + /* success */ + memcpy(bond_dev->dev_addr, sa->sa_data, bond_dev->addr_len); + return 0; + +unwind: + memcpy(tmp_sa.sa_data, bond_dev->dev_addr, bond_dev->addr_len); + tmp_sa.sa_family = bond_dev->type; + + /* unwind from head to the slave that failed */ + stop_at = slave; + bond_for_each_slave_from_to(bond, slave, i, bond->first_slave, stop_at) { + int tmp_res; + + tmp_res = slave->dev->set_mac_address(slave->dev, &tmp_sa); + if (tmp_res) { + dprintk("unwind err %d dev %s\n", tmp_res, + slave->dev->name); + } + } + + return res; +} + +static int bond_xmit_roundrobin(struct sk_buff *skb, struct net_device *bond_dev) +{ + struct bonding *bond = bond_dev->priv; + struct slave *slave, *start_at; + int i; + + read_lock(&bond->lock); + + if (!BOND_IS_OK(bond)) { + goto free_out; + } + + read_lock(&bond->curr_slave_lock); + slave = start_at = bond->curr_active_slave; + read_unlock(&bond->curr_slave_lock); + + if (!slave) { + goto free_out; + } + + bond_for_each_slave_from(bond, slave, i, start_at) { + if (IS_UP(slave->dev) && + (slave->link == BOND_LINK_UP) && + (slave->state == BOND_STATE_ACTIVE)) { + skb->dev = slave->dev; + skb->priority = 1; + dev_queue_xmit(skb); + + write_lock(&bond->curr_slave_lock); + bond->curr_active_slave = slave->next; + write_unlock(&bond->curr_slave_lock); + + goto out; + } + } + +out: + read_unlock(&bond->lock); + return 0; + +free_out: + /* no suitable interface, frame not sent */ + dev_kfree_skb(skb); + goto out; } /* - * Does not allocate but creates a /proc entry. - * Allowed to fail. + * in active-backup mode, we know that bond->curr_active_slave is always valid if + * the bond has a usable interface. */ -static int __init bond_init(struct net_device *dev) +static int bond_xmit_activebackup(struct sk_buff *skb, struct net_device *bond_dev) { - struct bonding *bond; - int count; + struct bonding *bond = bond_dev->priv; -#ifdef BONDING_DEBUG - printk (KERN_INFO "Begin bond_init for %s\n", dev->name); -#endif - bond = dev->priv; + /* if we are sending arp packets, try to at least + identify our own ip address */ + if (bond->params.arp_interval && !my_ip && + (skb->protocol == __constant_htons(ETH_P_ARP))) { + char *the_ip = (char *)skb->data + + sizeof(struct ethhdr) + + sizeof(struct arphdr) + + ETH_ALEN; + memcpy(&my_ip, the_ip, 4); + } - /* initialize rwlocks */ - rwlock_init(&bond->lock); - rwlock_init(&bond->ptrlock); + read_lock(&bond->lock); + read_lock(&bond->curr_slave_lock); - /* Initialize pointers */ - bond->next = bond->prev = (slave_t *)bond; - bond->current_slave = NULL; - bond->current_arp_slave = NULL; - bond->device = dev; + if (!BOND_IS_OK(bond)) { + goto free_out; + } + + if (bond->curr_active_slave) { /* one usable interface */ + skb->dev = bond->curr_active_slave->dev; + skb->priority = 1; + dev_queue_xmit(skb); + goto out; + } else { + goto free_out; + } +out: + read_unlock(&bond->curr_slave_lock); + read_unlock(&bond->lock); + return 0; - /* Initialize the device structure. */ - dev->set_mac_address = bond_set_mac_address; +free_out: + /* no suitable interface, frame not sent */ + dev_kfree_skb(skb); + goto out; +} - switch (bond_mode) { - case BOND_MODE_ACTIVEBACKUP: - dev->hard_start_xmit = bond_xmit_activebackup; - break; +/* + * in XOR mode, we determine the output device by performing xor on + * the source and destination hw adresses. If this device is not + * enabled, find the next slave following this xor slave. + */ +static int bond_xmit_xor(struct sk_buff *skb, struct net_device *bond_dev) +{ + struct bonding *bond = bond_dev->priv; + struct ethhdr *data = (struct ethhdr *)skb->data; + struct slave *slave, *start_at; + int slave_no; + int i; + + read_lock(&bond->lock); + + if (!BOND_IS_OK(bond)) { + goto free_out; + } + + slave_no = (data->h_dest[5]^bond_dev->dev_addr[5]) % bond->slave_cnt; + + bond_for_each_slave(bond, slave, i) { + slave_no--; + if (slave_no < 0) { + break; + } + } + + start_at = slave; + + bond_for_each_slave_from(bond, slave, i, start_at) { + if (IS_UP(slave->dev) && + (slave->link == BOND_LINK_UP) && + (slave->state == BOND_STATE_ACTIVE)) { + skb->dev = slave->dev; + skb->priority = 1; + dev_queue_xmit(skb); + + goto out; + } + } + +out: + read_unlock(&bond->lock); + return 0; + +free_out: + /* no suitable interface, frame not sent */ + dev_kfree_skb(skb); + goto out; +} + +/* + * in broadcast mode, we send everything to all usable interfaces. + */ +static int bond_xmit_broadcast(struct sk_buff *skb, struct net_device *bond_dev) +{ + struct bonding *bond = bond_dev->priv; + struct slave *slave, *start_at; + struct net_device *tx_dev = NULL; + int i; + + read_lock(&bond->lock); + + if (!BOND_IS_OK(bond)) { + goto free_out; + } + + read_lock(&bond->curr_slave_lock); + start_at = bond->curr_active_slave; + read_unlock(&bond->curr_slave_lock); + + if (!start_at) { + goto free_out; + } + + bond_for_each_slave_from(bond, slave, i, start_at) { + if (IS_UP(slave->dev) && + (slave->link == BOND_LINK_UP) && + (slave->state == BOND_STATE_ACTIVE)) { + if (tx_dev) { + struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC); + if (!skb2) { + printk(KERN_ERR DRV_NAME + ": Error: bond_xmit_broadcast(): " + "skb_clone() failed\n"); + continue; + } + + skb2->dev = tx_dev; + skb2->priority = 1; + dev_queue_xmit(skb2); + } + tx_dev = slave->dev; + } + } + + if (tx_dev) { + skb->dev = tx_dev; + skb->priority = 1; + dev_queue_xmit(skb); + } else { + goto free_out; + } + +out: + /* frame sent to all suitable interfaces */ + read_unlock(&bond->lock); + return 0; + +free_out: + /* no suitable interface, frame not sent */ + dev_kfree_skb(skb); + goto out; +} + +#ifdef CONFIG_NET_FASTROUTE +static int bond_accept_fastpath(struct net_device *bond_dev, struct dst_entry *dst) +{ + return -1; +} +#endif + +/*------------------------- Device initialization ---------------------------*/ + +/* + * set bond mode specific net device operations + */ +static inline void bond_set_mode_ops(struct net_device *bond_dev, int mode) +{ + switch (mode) { case BOND_MODE_ROUNDROBIN: - dev->hard_start_xmit = bond_xmit_roundrobin; + bond_dev->hard_start_xmit = bond_xmit_roundrobin; + break; + case BOND_MODE_ACTIVEBACKUP: + bond_dev->hard_start_xmit = bond_xmit_activebackup; break; case BOND_MODE_XOR: - dev->hard_start_xmit = bond_xmit_xor; + bond_dev->hard_start_xmit = bond_xmit_xor; break; case BOND_MODE_BROADCAST: - dev->hard_start_xmit = bond_xmit_broadcast; + bond_dev->hard_start_xmit = bond_xmit_broadcast; break; case BOND_MODE_8023AD: - dev->hard_start_xmit = bond_3ad_xmit_xor; + bond_dev->hard_start_xmit = bond_3ad_xmit_xor; break; case BOND_MODE_TLB: case BOND_MODE_ALB: - dev->hard_start_xmit = bond_alb_xmit; - dev->set_mac_address = bond_alb_set_mac_address; + bond_dev->hard_start_xmit = bond_alb_xmit; + bond_dev->set_mac_address = bond_alb_set_mac_address; break; default: - printk(KERN_ERR "Unknown bonding mode %d\n", bond_mode); - return -EINVAL; + /* Should never happen, mode already checked */ + printk(KERN_ERR DRV_NAME + ": Error: Unknown bonding mode %d\n", + mode); + break; } +} + +/* + * Does not allocate but creates a /proc entry. + * Allowed to fail. + */ +static int __init bond_init(struct net_device *bond_dev, struct bond_params *params) +{ + struct bonding *bond = bond_dev->priv; + + dprintk("Begin bond_init for %s\n", bond_dev->name); + + /* initialize rwlocks */ + rwlock_init(&bond->lock); + rwlock_init(&bond->curr_slave_lock); + + bond->params = *params; /* copy params struct */ - dev->get_stats = bond_get_stats; - dev->open = bond_open; - dev->stop = bond_close; - dev->set_multicast_list = set_multicast_list; - dev->do_ioctl = bond_ioctl; - dev->change_mtu = bond_change_mtu; - dev->tx_queue_len = 0; - dev->flags |= IFF_MASTER|IFF_MULTICAST; + /* Initialize pointers */ + bond->first_slave = NULL; + bond->curr_active_slave = NULL; + bond->current_arp_slave = NULL; + bond->primary_slave = NULL; + bond->dev = bond_dev; + + /* Initialize the device entry points */ + bond_dev->open = bond_open; + bond_dev->stop = bond_close; + bond_dev->get_stats = bond_get_stats; + bond_dev->do_ioctl = bond_do_ioctl; + bond_dev->set_multicast_list = bond_set_multicast_list; + bond_dev->change_mtu = bond_change_mtu; + bond_dev->set_mac_address = bond_set_mac_address; + + bond_set_mode_ops(bond_dev, bond->params.mode); + + bond_dev->destructor = free_netdev; #ifdef CONFIG_NET_FASTROUTE - dev->accept_fastpath = bond_accept_fastpath; + bond_dev->accept_fastpath = bond_accept_fastpath; #endif - printk(KERN_INFO "%s registered with", dev->name); - if (miimon > 0) { - printk(" MII link monitoring set to %d ms", miimon); - updelay /= miimon; - downdelay /= miimon; - } else { - printk("out MII link monitoring"); - } - printk(", in %s mode.\n", bond_mode_name()); + /* Initialize the device options */ + bond_dev->tx_queue_len = 0; + bond_dev->flags |= IFF_MASTER|IFF_MULTICAST; + - printk(KERN_INFO "%s registered with", dev->name); - if (arp_interval > 0) { - printk(" ARP monitoring set to %d ms with %d target(s):", - arp_interval, arp_ip_count); - for (count=0 ; countdestructor = free_netdev; - list_add_tail(&bond->bond_list, &bond_dev_list); return 0; } -/* -static int __init bond_probe(struct net_device *dev) +/* De-initialize device specific data. + * Caller must hold rtnl_lock. + */ +static inline void bond_deinit(struct net_device *bond_dev) { - bond_init(dev); - return 0; + struct bonding *bond = bond_dev->priv; + + list_del(&bond->bond_list); + +#ifdef CONFIG_PROC_FS + bond_remove_proc_entry(bond); +#endif } + +/* Unregister and free all bond devices. + * Caller must hold rtnl_lock. */ +static void bond_free_all(void) +{ + struct bonding *bond, *nxt; + + list_for_each_entry_safe(bond, nxt, &bond_dev_list, bond_list) { + struct net_device *bond_dev = bond->dev; + + unregister_netdevice(bond_dev); + bond_deinit(bond_dev); + } + +#ifdef CONFIG_PROC_FS + bond_destroy_proc_dir(); +#endif +} + +/*------------------------- Module initialization ---------------------------*/ /* * Convert string input module parms. Accept either the * number of the mode or its string name. */ -static inline int -bond_parse_parm(char *mode_arg, struct bond_parm_tbl *tbl) +static inline int bond_parse_parm(char *mode_arg, struct bond_parm_tbl *tbl) { int i; - for (i = 0; tbl[i].modename != NULL; i++) { + for (i = 0; tbl[i].modename; i++) { if ((isdigit(*mode_arg) && - tbl[i].mode == simple_strtol(mode_arg, NULL, 0)) || - (0 == strncmp(mode_arg, tbl[i].modename, - strlen(tbl[i].modename)))) { + tbl[i].mode == simple_strtol(mode_arg, NULL, 0)) || + (strncmp(mode_arg, tbl[i].modename, + strlen(tbl[i].modename)) == 0)) { return tbl[i].mode; } } @@ -4043,275 +3923,281 @@ return -1; } - -static int __init bonding_init(void) +static int bond_check_params(struct bond_params *params) { - int no; - int err; - - printk(KERN_INFO "%s", version); - /* * Convert string parameters. */ if (mode) { bond_mode = bond_parse_parm(mode, bond_mode_tbl); if (bond_mode == -1) { - printk(KERN_WARNING - "bonding_init(): Invalid bonding mode \"%s\"\n", + printk(KERN_ERR DRV_NAME + ": Error: Invalid bonding mode \"%s\"\n", mode == NULL ? "NULL" : mode); return -EINVAL; } } - if (USES_PRIMARY(bond_mode)) { - multicast_mode = BOND_MULTICAST_ACTIVE; - } else { - multicast_mode = BOND_MULTICAST_ALL; - } - - if (multicast) { - multicast_mode = bond_parse_parm(multicast, bond_mc_tbl); - if (multicast_mode == -1) { - printk(KERN_WARNING - "bonding_init(): Invalid multicast mode \"%s\"\n", - multicast == NULL ? "NULL" : multicast); - return -EINVAL; - } - } - if (lacp_rate) { if (bond_mode != BOND_MODE_8023AD) { - printk(KERN_WARNING - "lacp_rate param is irrelevant in mode %s\n", - bond_mode_name()); + printk(KERN_INFO DRV_NAME + ": lacp_rate param is irrelevant in mode %s\n", + bond_mode_name(bond_mode)); } else { lacp_fast = bond_parse_parm(lacp_rate, bond_lacp_tbl); if (lacp_fast == -1) { - printk(KERN_WARNING - "bonding_init(): Invalid lacp rate " - "\"%s\"\n", + printk(KERN_ERR DRV_NAME + ": Error: Invalid lacp rate \"%s\"\n", lacp_rate == NULL ? "NULL" : lacp_rate); - return -EINVAL; } } } if (max_bonds < 1 || max_bonds > INT_MAX) { - printk(KERN_WARNING - "bonding_init(): max_bonds (%d) not in range %d-%d, " - "so it was reset to BOND_DEFAULT_MAX_BONDS (%d)", + printk(KERN_WARNING DRV_NAME + ": Warning: max_bonds (%d) not in range %d-%d, so it " + "was reset to BOND_DEFAULT_MAX_BONDS (%d)", max_bonds, 1, INT_MAX, BOND_DEFAULT_MAX_BONDS); max_bonds = BOND_DEFAULT_MAX_BONDS; } if (miimon < 0) { - printk(KERN_WARNING - "bonding_init(): miimon module parameter (%d), " + printk(KERN_WARNING DRV_NAME + ": Warning: miimon module parameter (%d), " "not in range 0-%d, so it was reset to %d\n", miimon, INT_MAX, BOND_LINK_MON_INTERV); miimon = BOND_LINK_MON_INTERV; } if (updelay < 0) { - printk(KERN_WARNING - "bonding_init(): updelay module parameter (%d), " + printk(KERN_WARNING DRV_NAME + ": Warning: updelay module parameter (%d), " "not in range 0-%d, so it was reset to 0\n", updelay, INT_MAX); updelay = 0; } if (downdelay < 0) { - printk(KERN_WARNING - "bonding_init(): downdelay module parameter (%d), " + printk(KERN_WARNING DRV_NAME + ": Warning: downdelay module parameter (%d), " "not in range 0-%d, so it was reset to 0\n", downdelay, INT_MAX); downdelay = 0; } + if ((use_carrier != 0) && (use_carrier != 1)) { + printk(KERN_WARNING DRV_NAME + ": Warning: use_carrier module parameter (%d), " + "not of valid value (0/1), so it was set to 1\n", + use_carrier); + use_carrier = 1; + } + /* reset values for 802.3ad */ if (bond_mode == BOND_MODE_8023AD) { - if (arp_interval != 0) { - printk(KERN_WARNING "bonding_init(): ARP monitoring" - "can't be used simultaneously with 802.3ad, " - "disabling ARP monitoring\n"); - arp_interval = 0; - } - - if (miimon == 0) { - printk(KERN_ERR - "bonding_init(): miimon must be specified, " - "otherwise bonding will not detect link failure, " - "speed and duplex which are essential " - "for 802.3ad operation\n"); - printk(KERN_ERR "Forcing miimon to 100msec\n"); + if (!miimon) { + printk(KERN_WARNING DRV_NAME + ": Warning: miimon must be specified, " + "otherwise bonding will not detect link " + "failure, speed and duplex which are " + "essential for 802.3ad operation\n"); + printk(KERN_WARNING "Forcing miimon to 100msec\n"); miimon = 100; } - - if (multicast_mode != BOND_MULTICAST_ALL) { - printk(KERN_ERR - "bonding_init(): Multicast mode must " - "be set to ALL for 802.3ad\n"); - printk(KERN_ERR "Forcing Multicast mode to ALL\n"); - multicast_mode = BOND_MULTICAST_ALL; - } } /* reset values for TLB/ALB */ if ((bond_mode == BOND_MODE_TLB) || (bond_mode == BOND_MODE_ALB)) { - if (miimon == 0) { - printk(KERN_ERR - "bonding_init(): miimon must be specified, " - "otherwise bonding will not detect link failure " - "and link speed which are essential " + if (!miimon) { + printk(KERN_WARNING DRV_NAME + ": Warning: miimon must be specified, " + "otherwise bonding will not detect link " + "failure and link speed which are essential " "for TLB/ALB load balancing\n"); - printk(KERN_ERR "Forcing miimon to 100msec\n"); + printk(KERN_WARNING "Forcing miimon to 100msec\n"); miimon = 100; } - - if (multicast_mode != BOND_MULTICAST_ACTIVE) { - printk(KERN_ERR - "bonding_init(): Multicast mode must " - "be set to ACTIVE for TLB/ALB\n"); - printk(KERN_ERR "Forcing Multicast mode to ACTIVE\n"); - multicast_mode = BOND_MULTICAST_ACTIVE; - } } if (bond_mode == BOND_MODE_ALB) { - printk(KERN_INFO - "In ALB mode you might experience client disconnections" - " upon reconnection of a link if the bonding module" - " updelay parameter (%d msec) is incompatible with the" - " forwarding delay time of the switch\n", updelay); + printk(KERN_NOTICE DRV_NAME + ": In ALB mode you might experience client " + "disconnections upon reconnection of a link if the " + "bonding module updelay parameter (%d msec) is " + "incompatible with the forwarding delay time of the " + "switch\n", + updelay); } - if (miimon == 0) { - if ((updelay != 0) || (downdelay != 0)) { + if (!miimon) { + if (updelay || downdelay) { /* just warn the user the up/down delay will have * no effect since miimon is zero... */ - printk(KERN_WARNING - "bonding_init(): miimon module parameter not " - "set and updelay (%d) or downdelay (%d) module " + printk(KERN_WARNING DRV_NAME + ": Warning: miimon module parameter not set " + "and updelay (%d) or downdelay (%d) module " "parameter is set; updelay and downdelay have " "no effect unless miimon is set\n", - updelay, downdelay); + updelay, downdelay); } } else { /* don't allow arp monitoring */ - if (arp_interval != 0) { - printk(KERN_WARNING - "bonding_init(): miimon (%d) and arp_interval " - "(%d) can't be used simultaneously, " - "disabling ARP monitoring\n", - miimon, arp_interval); + if (arp_interval) { + printk(KERN_WARNING DRV_NAME + ": Warning: miimon (%d) and arp_interval (%d) " + "can't be used simultaneously, disabling ARP " + "monitoring\n", + miimon, arp_interval); arp_interval = 0; } if ((updelay % miimon) != 0) { - /* updelay will be rounded in bond_init() when it - * is divided by miimon, we just inform user here - */ - printk(KERN_WARNING - "bonding_init(): updelay (%d) is not a multiple " + printk(KERN_WARNING DRV_NAME + ": Warning: updelay (%d) is not a multiple " "of miimon (%d), updelay rounded to %d ms\n", - updelay, miimon, (updelay / miimon) * miimon); + updelay, miimon, (updelay / miimon) * miimon); } + updelay /= miimon; + if ((downdelay % miimon) != 0) { - /* downdelay will be rounded in bond_init() when it - * is divided by miimon, we just inform user here - */ - printk(KERN_WARNING - "bonding_init(): downdelay (%d) is not a " - "multiple of miimon (%d), downdelay rounded " - "to %d ms\n", - downdelay, miimon, + printk(KERN_WARNING DRV_NAME + ": Warning: downdelay (%d) is not a multiple " + "of miimon (%d), downdelay rounded to %d ms\n", + downdelay, miimon, (downdelay / miimon) * miimon); } + + downdelay /= miimon; } if (arp_interval < 0) { - printk(KERN_WARNING - "bonding_init(): arp_interval module parameter (%d), " - "not in range 0-%d, so it was reset to %d\n", + printk(KERN_WARNING DRV_NAME + ": Warning: arp_interval module parameter (%d) " + ", not in range 0-%d, so it was reset to %d\n", arp_interval, INT_MAX, BOND_LINK_ARP_INTERV); arp_interval = BOND_LINK_ARP_INTERV; } - for (arp_ip_count=0 ; - (arp_ip_count < MAX_ARP_IP_TARGETS) && arp_ip_target[arp_ip_count]; - arp_ip_count++ ) { + for (arp_ip_count = 0; + (arp_ip_count < BOND_MAX_ARP_TARGETS) && arp_ip_target[arp_ip_count]; + arp_ip_count++) { /* not complete check, but should be good enough to catch mistakes */ - if (!isdigit(arp_ip_target[arp_ip_count][0])) { - printk(KERN_WARNING - "bonding_init(): bad arp_ip_target module " - "parameter (%s), ARP monitoring will not be " - "performed\n", - arp_ip_target[arp_ip_count]); - arp_interval = 0; - } else { - u32 ip = in_aton(arp_ip_target[arp_ip_count]); + if (!isdigit(arp_ip_target[arp_ip_count][0])) { + printk(KERN_WARNING DRV_NAME + ": Warning: bad arp_ip_target module parameter " + "(%s), ARP monitoring will not be performed\n", + arp_ip_target[arp_ip_count]); + arp_interval = 0; + } else { + u32 ip = in_aton(arp_ip_target[arp_ip_count]); arp_target[arp_ip_count] = ip; } - } - + } - if ( (arp_interval > 0) && (arp_ip_count==0)) { + if (arp_interval && !arp_ip_count) { /* don't allow arping if no arp_ip_target given... */ - printk(KERN_WARNING - "bonding_init(): arp_interval module parameter " - "(%d) specified without providing an arp_ip_target " + printk(KERN_WARNING DRV_NAME + ": Warning: arp_interval module parameter (%d) " + "specified without providing an arp_ip_target " "parameter, arp_interval was reset to 0\n", arp_interval); arp_interval = 0; } - if ((miimon == 0) && (arp_interval == 0)) { + if (miimon) { + printk(KERN_INFO DRV_NAME + ": MII link monitoring set to %d ms\n", + miimon); + } else if (arp_interval) { + int i; + + printk(KERN_INFO DRV_NAME + ": ARP monitoring set to %d ms with %d target(s):", + arp_interval, arp_ip_count); + + for (i = 0; i < arp_ip_count; i++) + printk (" %s", arp_ip_target[i]); + + printk("\n"); + + } else { /* miimon and arp_interval not set, we need one so things * work as expected, see bonding.txt for details */ - printk(KERN_ERR - "bonding_init(): either miimon or " - "arp_interval and arp_ip_target module parameters " - "must be specified, otherwise bonding will not detect " - "link failures! see bonding.txt for details.\n"); + printk(KERN_WARNING DRV_NAME + ": Warning: either miimon or arp_interval and " + "arp_ip_target module parameters must be specified, " + "otherwise bonding will not detect link failures! see " + "bonding.txt for details.\n"); } - if ((primary != NULL) && !USES_PRIMARY(bond_mode)) { + if (primary && !USES_PRIMARY(bond_mode)) { /* currently, using a primary only makes sense * in active backup, TLB or ALB modes */ - printk(KERN_WARNING - "bonding_init(): %s primary device specified but has " - "no effect in %s mode\n", - primary, bond_mode_name()); + printk(KERN_WARNING DRV_NAME + ": Warning: %s primary device specified but has no " + "effect in %s mode\n", + primary, bond_mode_name(bond_mode)); primary = NULL; } + /* fill params struct with the proper values */ + params->mode = bond_mode; + params->miimon = miimon; + params->arp_interval = arp_interval; + params->updelay = updelay; + params->downdelay = downdelay; + params->use_carrier = use_carrier; + params->lacp_fast = lacp_fast; + params->primary[0] = 0; + + if (primary) { + strncpy(params->primary, primary, IFNAMSIZ); + params->primary[IFNAMSIZ - 1] = 0; + } + + memcpy(params->arp_targets, arp_target, sizeof(arp_target)); + + return 0; +} + +static int __init bonding_init(void) +{ + struct bond_params params; + int i; + int res; + + printk(KERN_INFO "%s", version); + + res = bond_check_params(¶ms); + if (res) { + return res; + } + rtnl_lock(); #ifdef CONFIG_PROC_FS bond_create_proc_dir(); #endif - err = 0; - for (no = 0; no < max_bonds; no++) { - struct net_device *dev; - - dev = alloc_netdev(sizeof(struct bonding), "", ether_setup); - if (!dev) { - err = -ENOMEM; + for (i = 0; i < max_bonds; i++) { + struct net_device *bond_dev; + + bond_dev = alloc_netdev(sizeof(struct bonding), "", ether_setup); + if (!bond_dev) { + res = -ENOMEM; goto out_err; } - err = dev_alloc_name(dev, "bond%d"); - if (err < 0) { - free_netdev(dev); + res = dev_alloc_name(bond_dev, "bond%d"); + if (res < 0) { + free_netdev(bond_dev); goto out_err; } @@ -4319,18 +4205,18 @@ * /proc files), but before register_netdevice(), because we * need to set function pointers. */ - err = bond_init(dev); - if (err < 0) { - free_netdev(dev); + res = bond_init(bond_dev, ¶ms); + if (res < 0) { + free_netdev(bond_dev); goto out_err; } - SET_MODULE_OWNER(dev); + SET_MODULE_OWNER(bond_dev); - err = register_netdevice(dev); - if (err < 0) { - bond_deinit(dev); - free_netdev(dev); + res = register_netdevice(bond_dev); + if (res < 0) { + bond_deinit(bond_dev); + free_netdev(bond_dev); goto out_err; } } @@ -4346,7 +4232,7 @@ rtnl_unlock(); - return err; + return res; } static void __exit bonding_exit(void) @@ -4362,6 +4248,8 @@ module_exit(bonding_exit); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION(DRV_DESCRIPTION ", v" DRV_VERSION); +MODULE_AUTHOR("Thomas Davis, tadavis@lbl.gov and many others"); +MODULE_SUPPORTED_DEVICE("most ethernet devices"); /* * Local variables: @@ -4370,3 +4258,4 @@ * tab-width: 8 * End: */ + diff -Nru a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h --- a/drivers/net/bonding/bonding.h Thu Jan 22 18:59:24 2004 +++ b/drivers/net/bonding/bonding.h Thu Jan 22 18:59:24 2004 @@ -9,7 +9,7 @@ * * This software may be used and distributed according to the terms * of the GNU Public License, incorporated herein by reference. - * + * * * 2003/03/18 - Amir Noam , * Tsippy Mendelson and @@ -22,159 +22,220 @@ * * 2003/05/01 - Shmulik Hen * - Added support for Transmit load balancing mode. + * + * 2003/12/01 - Shmulik Hen + * - Code cleanup and style changes */ - + #ifndef _LINUX_BONDING_H #define _LINUX_BONDING_H #include #include +#include #include "bond_3ad.h" #include "bond_alb.h" -#ifdef BONDING_DEBUG +#define DRV_VERSION "2.5.4" +#define DRV_RELDATE "December 30, 2003" +#define DRV_NAME "bonding" +#define DRV_DESCRIPTION "Ethernet Channel Bonding Driver" -// use this like so: BOND_PRINT_DBG(("foo = %d, bar = %d", foo, bar)); -#define BOND_PRINT_DBG(X) \ -do { \ - printk(KERN_DEBUG "%s (%d)", __FUNCTION__, __LINE__); \ - printk X; \ - printk("\n"); \ -} while(0) +#define BOND_MAX_ARP_TARGETS 16 +#ifdef BONDING_DEBUG +#define dprintk(fmt, args...) \ + printk(KERN_DEBUG \ + DRV_NAME ": %s() %d: " fmt, __FUNCTION__, __LINE__ , ## args ) #else -#define BOND_PRINT_DBG(X) +#define dprintk(fmt, args...) #endif /* BONDING_DEBUG */ -#define IS_UP(dev) ((((dev)->flags & (IFF_UP)) == (IFF_UP)) && \ - (netif_running(dev) && netif_carrier_ok(dev))) +#define IS_UP(dev) \ + ((((dev)->flags & IFF_UP) == IFF_UP) && \ + netif_running(dev) && \ + netif_carrier_ok(dev)) + +/* + * Checks whether bond is ready for transmit. + * + * Caller must hold bond->lock + */ +#define BOND_IS_OK(bond) \ + (((bond)->dev->flags & IFF_UP) && \ + netif_running((bond)->dev) && \ + ((bond)->slave_cnt > 0)) -/* Checks whether the dev is ready for transmit. We do not check netif_running - * since a device can be stopped by the driver for short periods of time for - * maintainance. dev_queue_xmit() handles this by queing the packet until the - * the dev is running again. Keeping packets ordering requires sticking the - * same dev as much as possible - */ -#define SLAVE_IS_OK(slave) \ - ((((slave)->dev->flags & (IFF_UP)) == (IFF_UP)) && \ - netif_carrier_ok((slave)->dev) && \ +/* + * Checks whether slave is ready for transmit. + */ +#define SLAVE_IS_OK(slave) \ + (((slave)->dev->flags & IFF_UP) && \ + netif_running((slave)->dev) && \ ((slave)->link == BOND_LINK_UP) && \ ((slave)->state == BOND_STATE_ACTIVE)) -typedef struct slave { +#define USES_PRIMARY(mode) \ + (((mode) == BOND_MODE_ACTIVEBACKUP) || \ + ((mode) == BOND_MODE_TLB) || \ + ((mode) == BOND_MODE_ALB)) + +/* + * Less bad way to call ioctl from within the kernel; this needs to be + * done some other way to get the call out of interrupt context. + * Needs "ioctl" variable to be supplied by calling context. + */ +#define IOCTL(dev, arg, cmd) ({ \ + int res = 0; \ + mm_segment_t fs = get_fs(); \ + set_fs(get_ds()); \ + res = ioctl(dev, arg, cmd); \ + set_fs(fs); \ + res; }) + +/** + * bond_for_each_slave_from - iterate the slaves list from a starting point + * @bond: the bond holding this list. + * @pos: current slave. + * @cnt: counter for max number of moves + * @start: starting point. + * + * Caller must hold bond->lock + */ +#define bond_for_each_slave_from(bond, pos, cnt, start) \ + for (cnt = 0, pos = start; \ + cnt < (bond)->slave_cnt; \ + cnt++, pos = (pos)->next) + +/** + * bond_for_each_slave_from_to - iterate the slaves list from start point to stop point + * @bond: the bond holding this list. + * @pos: current slave. + * @cnt: counter for number max of moves + * @start: start point. + * @stop: stop point. + * + * Caller must hold bond->lock + */ +#define bond_for_each_slave_from_to(bond, pos, cnt, start, stop) \ + for (cnt = 0, pos = start; \ + ((cnt < (bond)->slave_cnt) && (pos != (stop)->next)); \ + cnt++, pos = (pos)->next) + +/** + * bond_for_each_slave - iterate the slaves list from head + * @bond: the bond holding this list. + * @pos: current slave. + * @cnt: counter for max number of moves + * + * Caller must hold bond->lock + */ +#define bond_for_each_slave(bond, pos, cnt) \ + bond_for_each_slave_from(bond, pos, cnt, (bond)->first_slave) + + +struct bond_params { + int mode; + int miimon; + int arp_interval; + int use_carrier; + int updelay; + int downdelay; + int lacp_fast; + char primary[IFNAMSIZ]; + u32 arp_targets[BOND_MAX_ARP_TARGETS]; +}; + +struct slave { + struct net_device *dev; /* first - usefull for panic debug */ struct slave *next; struct slave *prev; - struct net_device *dev; - short delay; - unsigned long jiffies; - char link; /* one of BOND_LINK_XXXX */ - char state; /* one of BOND_STATE_XXXX */ - unsigned short original_flags; - u32 link_failure_count; + s16 delay; + u32 jiffies; + s8 link; /* one of BOND_LINK_XXXX */ + s8 state; /* one of BOND_STATE_XXXX */ + u32 original_flags; + u32 link_failure_count; u16 speed; u8 duplex; u8 perm_hwaddr[ETH_ALEN]; struct ad_slave_info ad_info; /* HUGE - better to dynamically alloc */ struct tlb_slave_info tlb_info; -} slave_t; +}; /* * Here are the locking policies for the two bonding locks: * * 1) Get bond->lock when reading/writing slave list. - * 2) Get bond->ptrlock when reading/writing bond->current_slave. + * 2) Get bond->curr_slave_lock when reading/writing bond->curr_active_slave. * (It is unnecessary when the write-lock is put with bond->lock.) - * 3) When we lock with bond->ptrlock, we must lock with bond->lock + * 3) When we lock with bond->curr_slave_lock, we must lock with bond->lock * beforehand. */ -typedef struct bonding { - slave_t *next; - slave_t *prev; - slave_t *current_slave; - slave_t *primary_slave; - slave_t *current_arp_slave; - __s32 slave_cnt; +struct bonding { + struct net_device *dev; /* first - usefull for panic debug */ + struct slave *first_slave; + struct slave *curr_active_slave; + struct slave *current_arp_slave; + struct slave *primary_slave; + s32 slave_cnt; /* never change this value outside the attach/detach wrappers */ rwlock_t lock; - rwlock_t ptrlock; - struct timer_list mii_timer; - struct timer_list arp_timer; - struct net_device_stats stats; + rwlock_t curr_slave_lock; + struct timer_list mii_timer; + struct timer_list arp_timer; + s8 kill_timers; + struct net_device_stats stats; #ifdef CONFIG_PROC_FS - struct proc_dir_entry *bond_proc_file; - char procdir_name[IFNAMSIZ]; + struct proc_dir_entry *proc_entry; + char proc_file_name[IFNAMSIZ]; #endif /* CONFIG_PROC_FS */ - struct list_head bond_list; - struct net_device *device; - struct dev_mc_list *mc_list; - unsigned short flags; - struct ad_bond_info ad_info; - struct alb_bond_info alb_info; -} bonding_t; - -/* Forward declarations */ -void bond_set_slave_active_flags(slave_t *slave); -void bond_set_slave_inactive_flags(slave_t *slave); - -/** - * These functions can be used for iterating the slave list - * (which is circular) - * Caller must hold bond lock for read - */ -extern inline struct slave* -bond_get_first_slave(struct bonding *bond) -{ - /* if there are no slaves return NULL */ - if (bond->next == (slave_t *)bond) { - return NULL; - } - return bond->next; -} - -/** - * Caller must hold bond lock for read - */ -extern inline struct slave* -bond_get_next_slave(struct bonding *bond, struct slave *slave) -{ - /* If we have reached the last slave return NULL */ - if (slave->next == bond->next) { - return NULL; - } - return slave->next; -} + struct list_head bond_list; + struct dev_mc_list *mc_list; + u16 flags; + struct ad_bond_info ad_info; + struct alb_bond_info alb_info; + struct bond_params params; +}; /** * Returns NULL if the net_device does not belong to any of the bond's slaves * * Caller must hold bond lock for read */ -extern inline struct slave* -bond_get_slave_by_dev(struct bonding *bond, struct net_device *slave_dev) +extern inline struct slave *bond_get_slave_by_dev(struct bonding *bond, struct net_device *slave_dev) { - struct slave *our_slave = bond->next; + struct slave *slave = NULL; + int i; - /* check if the list of slaves is empty */ - if (our_slave == (slave_t *)bond) { - return NULL; - } - - for (; our_slave; our_slave = bond_get_next_slave(bond, our_slave)) { - if (our_slave->dev == slave_dev) { + bond_for_each_slave(bond, slave, i) { + if (slave->dev == slave_dev) { break; } } - return our_slave; + + return slave; } -extern inline struct bonding* -bond_get_bond_by_slave(struct slave *slave) +extern inline struct bonding *bond_get_bond_by_slave(struct slave *slave) { if (!slave || !slave->dev->master) { return NULL; } - return (struct bonding *)(slave->dev->master->priv); + return (struct bonding *)slave->dev->master->priv; +} + +extern inline void bond_set_slave_inactive_flags(struct slave *slave) +{ + slave->state = BOND_STATE_BACKUP; + slave->dev->flags |= IFF_NOARP; +} + +extern inline void bond_set_slave_active_flags(struct slave *slave) +{ + slave->state = BOND_STATE_ACTIVE; + slave->dev->flags &= ~IFF_NOARP; } #endif /* _LINUX_BONDING_H */ diff -Nru a/drivers/net/cs89x0.c b/drivers/net/cs89x0.c --- a/drivers/net/cs89x0.c Thu Jan 22 18:59:26 2004 +++ b/drivers/net/cs89x0.c Thu Jan 22 18:59:26 2004 @@ -212,9 +212,7 @@ /* Index to functions, as function prototypes. */ -extern int cs89x0_probe(struct net_device *dev); - -static int cs89x0_probe1(struct net_device *dev, int ioaddr); +static int cs89x0_probe1(struct net_device *dev, int ioaddr, int modular); static int net_open(struct net_device *dev); static int net_send_packet(struct sk_buff *skb, struct net_device *dev); static irqreturn_t net_interrupt(int irq, void *dev_id, struct pt_regs *regs); @@ -274,27 +272,51 @@ Return 0 on success. */ -int __init cs89x0_probe(struct net_device *dev) +struct net_device * __init cs89x0_probe(int unit) { - int i; - int base_addr = dev ? dev->base_addr : 0; - - SET_MODULE_OWNER(dev); + struct net_device *dev = alloc_etherdev(sizeof(struct net_local)); + unsigned *port; + int err = 0; + int irq; + int io; + + if (!dev) + return ERR_PTR(-ENODEV); + + sprintf(dev->name, "eth%d", unit); + netdev_boot_setup_check(dev); + io = dev->base_addr; + irq = dev->irq; if (net_debug) - printk("cs89x0:cs89x0_probe(0x%x)\n", base_addr); + printk("cs89x0:cs89x0_probe(0x%x)\n", io); - if (base_addr > 0x1ff) /* Check a single specified location. */ - return cs89x0_probe1(dev, base_addr); - else if (base_addr != 0) /* Don't probe at all. */ - return -ENXIO; - - for (i = 0; netcard_portlist[i]; i++) { - if (cs89x0_probe1(dev, netcard_portlist[i]) == 0) - return 0; + if (io > 0x1ff) { /* Check a single specified location. */ + err = cs89x0_probe1(dev, io, 0); + } else if (io != 0) { /* Don't probe at all. */ + err = -ENXIO; + } else { + for (port = netcard_portlist; *port; port++) { + if (cs89x0_probe1(dev, *port, 0) == 0) + break; + dev->irq = irq; + } + if (!*port) + err = -ENODEV; } + if (err) + goto out; + err = register_netdev(dev); + if (err) + goto out1; + return dev; +out1: + outw(PP_ChipID, dev->base_addr + ADD_PORT); + release_region(dev->base_addr, NETCARD_IO_EXTENT); +out: + free_netdev(dev); printk(KERN_WARNING "cs89x0: no cs8900 or cs8920 detected. Be sure to disable PnP with SETUP\n"); - return -ENODEV; + return ERR_PTR(err); } static int @@ -375,39 +397,34 @@ */ static int __init -cs89x0_probe1(struct net_device *dev, int ioaddr) +cs89x0_probe1(struct net_device *dev, int ioaddr, int modular) { - struct net_local *lp; + struct net_local *lp = (struct net_local *)dev->priv; static unsigned version_printed; int i; unsigned rev_type = 0; int eeprom_buff[CHKSUM_LEN]; int retval; + SET_MODULE_OWNER(dev); /* Initialize the device structure. */ - if (dev->priv == NULL) { - dev->priv = kmalloc(sizeof(struct net_local), GFP_KERNEL); - if (dev->priv == 0) { - retval = -ENOMEM; - goto out; - } - lp = (struct net_local *)dev->priv; + if (!modular) { memset(lp, 0, sizeof(*lp)); spin_lock_init(&lp->lock); -#if !defined(MODULE) && (ALLOW_DMA != 0) +#ifndef MODULE +#if ALLOW_DMA if (g_cs89x0_dma) { lp->use_dma = 1; lp->dma = g_cs89x0_dma; lp->dmasize = 16; /* Could make this an option... */ } #endif -#ifndef MODULE lp->force = g_cs89x0_media__force; #endif } - lp = (struct net_local *)dev->priv; /* Grab the region so we can find another board if autoIRQ fails. */ + /* WTF is going on here? */ if (!request_region(ioaddr & ~3, NETCARD_IO_EXTENT, dev->name)) { printk(KERN_ERR "%s: request_region(0x%x, 0x%x) failed\n", dev->name, ioaddr, NETCARD_IO_EXTENT); @@ -696,9 +713,6 @@ dev->set_multicast_list = set_multicast_list; dev->set_mac_address = set_mac_address; - /* Fill in the fields of the device structure with ethernet values. */ - ether_setup(dev); - printk("\n"); if (net_debug) printk("cs89x0_probe1() successful\n"); @@ -706,9 +720,6 @@ out2: release_region(ioaddr & ~3, NETCARD_IO_EXTENT); out1: - kfree(dev->priv); - dev->priv = 0; -out: return retval; } @@ -1655,7 +1666,7 @@ #ifdef MODULE -static struct net_device dev_cs89x0; +static struct net_device *dev_cs89x0; /* * Support the 'debug' module parm even if we're compiled for non-debug to @@ -1733,6 +1744,7 @@ int init_module(void) { + struct net_device *dev = alloc_etherdev(sizeof(struct net_local)); struct net_local *lp; int ret = 0; @@ -1741,18 +1753,12 @@ #else debug = 0; #endif - - dev_cs89x0.irq = irq; - dev_cs89x0.base_addr = io; - - dev_cs89x0.init = cs89x0_probe; - dev_cs89x0.priv = kmalloc(sizeof(struct net_local), GFP_KERNEL); - if (dev_cs89x0.priv == 0) { - printk(KERN_ERR "cs89x0.c: Out of memory.\n"); + if (!dev) return -ENOMEM; - } - memset(dev_cs89x0.priv, 0, sizeof(struct net_local)); - lp = (struct net_local *)dev_cs89x0.priv; + + dev->irq = irq; + dev->base_addr = io; + lp = dev->priv; #if ALLOW_DMA if (use_dma) { @@ -1782,7 +1788,10 @@ printk(KERN_ERR "cs89x0.c: Append io=0xNNN\n"); ret = -EPERM; goto out; - } + } else if (io <= 0x1ff) { + ret = -ENXIO; + goto out; + } #if ALLOW_DMA if (use_dma && dmasize != 16 && dmasize != 64) { @@ -1791,30 +1800,31 @@ goto out; } #endif + ret = cs89x0_probe1(dev, io, 1); + if (ret) + goto out; - if (register_netdev(&dev_cs89x0) != 0) { + if (register_netdev(dev) != 0) { printk(KERN_ERR "cs89x0.c: No card found at 0x%x\n", io); ret = -ENXIO; + outw(PP_ChipID, dev->base_addr + ADD_PORT); + release_region(dev->base_addr, NETCARD_IO_EXTENT); goto out; } + dev_cs89x0 = dev; + return 0; out: - if (ret) - kfree(dev_cs89x0.priv); + free_netdev(dev); return ret; } void cleanup_module(void) { - if (dev_cs89x0.priv != NULL) { - /* Free up the private structure, or leak memory :-) */ - unregister_netdev(&dev_cs89x0); - outw(PP_ChipID, dev_cs89x0.base_addr + ADD_PORT); - kfree(dev_cs89x0.priv); - dev_cs89x0.priv = NULL; /* gets re-allocated by cs89x0_probe1 */ - /* If we don't do this, we can't re-insmod it later. */ - release_region(dev_cs89x0.base_addr, NETCARD_IO_EXTENT); - } + unregister_netdev(dev_cs89x0); + outw(PP_ChipID, dev_cs89x0->base_addr + ADD_PORT); + release_region(dev_cs89x0->base_addr, NETCARD_IO_EXTENT); + free_netdev(dev_cs89x0); } #endif /* MODULE */ diff -Nru a/drivers/net/de600.c b/drivers/net/de600.c --- a/drivers/net/de600.c Thu Jan 22 18:59:26 2004 +++ b/drivers/net/de600.c Thu Jan 22 18:59:26 2004 @@ -99,7 +99,7 @@ static volatile int tx_fifo_out; static volatile int free_tx_pages = TX_PAGES; static int was_down; -static spinlock_t de600_lock; +static spinlock_t de600_lock = SPIN_LOCK_UNLOCKED; static inline u8 de600_read_status(struct net_device *dev) { @@ -398,20 +398,31 @@ */ } -int __init de600_probe(struct net_device *dev) +static struct net_device * __init de600_probe(void) { int i; - static struct net_device_stats de600_netstats; - /*dev->priv = kmalloc(sizeof(struct net_device_stats), GFP_KERNEL);*/ + struct net_device *dev; + int err; + + dev = alloc_etherdev(sizeof(struct net_device_stats)); + if (!dev) + return ERR_PTR(-ENOMEM); SET_MODULE_OWNER(dev); + if (!request_region(DE600_IO, 3, "de600")) { + printk(KERN_WARNING "DE600: port 0x%x busy\n", DE600_IO); + err = -EBUSY; + goto out; + } + printk(KERN_INFO "%s: D-Link DE-600 pocket adapter", dev->name); /* Alpha testers must have the version number to report bugs. */ if (de600_debug > 1) printk(version); /* probe for adapter */ + err = -ENODEV; rx_page = 0; select_nic(); (void)de600_read_status(dev); @@ -419,7 +430,7 @@ de600_put_command(STOP_RESET); if (de600_read_status(dev) & 0xf0) { printk(": not at I/O %#3x.\n", DATA_PORT); - return -ENODEV; + goto out1; } /* @@ -444,12 +455,7 @@ dev->dev_addr[3] |= 0x70; } else { printk(" not identified in the printer port\n"); - return -ENODEV; - } - - if (!request_region(DE600_IO, 3, "de600")) { - printk(KERN_WARNING "DE600: port 0x%x busy\n", DE600_IO); - return -EBUSY; + goto out1; } printk(", Ethernet Address: %02X", dev->dev_addr[0]); @@ -457,22 +463,27 @@ printk(":%02X",dev->dev_addr[i]); printk("\n"); - /* Initialize the device structure. */ - dev->priv = &de600_netstats; - - memset(dev->priv, 0, sizeof(struct net_device_stats)); dev->get_stats = get_stats; dev->open = de600_open; dev->stop = de600_close; dev->hard_start_xmit = &de600_start_xmit; - ether_setup(dev); - dev->flags&=~IFF_MULTICAST; select_prn(); - return 0; + + err = register_netdev(dev); + if (err) + goto out1; + + return dev; + +out1: + release_region(DE600_IO, 3); +out: + free_netdev(dev); + return ERR_PTR(err); } static int adapter_init(struct net_device *dev) @@ -527,21 +538,21 @@ return 0; /* OK */ } -static struct net_device de600_dev; +static struct net_device *de600_dev; static int __init de600_init(void) { - spin_lock_init(&de600_lock); - de600_dev.init = de600_probe; - if (register_netdev(&de600_dev) != 0) - return -EIO; + de600_dev = de600_probe(); + if (IS_ERR(de600_dev)) + return PTR_ERR(de600_dev); return 0; } static void __exit de600_exit(void) { - unregister_netdev(&de600_dev); + unregister_netdev(de600_dev); release_region(DE600_IO, 3); + free_netdev(de600_dev); } module_init(de600_init); diff -Nru a/drivers/net/de600.h b/drivers/net/de600.h --- a/drivers/net/de600.h Thu Jan 22 18:59:25 2004 +++ b/drivers/net/de600.h Thu Jan 22 18:59:25 2004 @@ -131,7 +131,6 @@ /* Initialization */ static void trigger_interrupt(struct net_device *dev); -int de600_probe(struct net_device *dev); static int adapter_init(struct net_device *dev); /* diff -Nru a/drivers/net/de620.c b/drivers/net/de620.c --- a/drivers/net/de620.c Thu Jan 22 18:59:25 2004 +++ b/drivers/net/de620.c Thu Jan 22 18:59:25 2004 @@ -226,7 +226,6 @@ /* Initialization */ static int adapter_init(struct net_device *); -int de620_probe(struct net_device *); static int read_eeprom(struct net_device *); @@ -814,11 +813,16 @@ * * Check if there is a DE-620 connected */ -int __init de620_probe(struct net_device *dev) +struct net_device * __init de620_probe(int unit) { - static struct net_device_stats de620_netstats; - int i; byte checkbyte = 0xa5; + struct net_device *dev; + int err = -ENOMEM; + int i; + + dev = alloc_etherdev(sizeof(struct net_device_stats)); + if (!dev) + goto out; SET_MODULE_OWNER(dev); @@ -831,11 +835,23 @@ dev->base_addr = io; dev->irq = irq; + /* allow overriding parameters on command line */ + if (unit >= 0) { + sprintf(dev->name, "eth%d", unit); + netdev_boot_setup_check(dev); + } + if (de620_debug) printk(version); printk(KERN_INFO "D-Link DE-620 pocket adapter"); + if (!request_region(dev->base_addr, 3, "de620")) { + printk(" io 0x%3lX, which is busy.\n", dev->base_addr); + err = -EBUSY; + goto out1; + } + /* Initially, configure basic nibble mode, so we can read the EEPROM */ NIC_Cmd = DEF_NIC_CMD; de620_set_register(dev, W_EIP, EIPRegister); @@ -846,12 +862,8 @@ if ((checkbyte != 0xa5) || (read_eeprom(dev) != 0)) { printk(" not identified in the printer port\n"); - return -ENODEV; - } - - if (!request_region(dev->base_addr, 3, "de620")) { - printk(KERN_ERR "io 0x%3lX, which is busy.\n", dev->base_addr); - return -EBUSY; + err = -ENODEV; + goto out2; } /* else, got it! */ @@ -870,10 +882,6 @@ else printk(" UTP)\n"); - /* Initialize the device structure. */ - dev->priv = &de620_netstats; - - memset(dev->priv, 0, sizeof(struct net_device_stats)); dev->get_stats = get_stats; dev->open = de620_open; dev->stop = de620_close; @@ -884,8 +892,6 @@ /* base_addr and irq are already set, see above! */ - ether_setup(dev); - /* dump eeprom */ if (de620_debug) { printk("\nEEPROM contents:\n"); @@ -899,7 +905,17 @@ printk("SCR = 0x%02x\n", nic_data.SCR); } - return 0; + err = register_netdev(dev); + if (err) + goto out2; + return dev; + +out2: + release_region(dev->base_addr, 3); +out1: + free_netdev(dev); +out: + return ERR_PTR(err); } /********************************** @@ -994,20 +1010,21 @@ * */ #ifdef MODULE -static struct net_device de620_dev; +static struct net_device *de620_dev; int init_module(void) { - de620_dev.init = de620_probe; - if (register_netdev(&de620_dev) != 0) - return -EIO; + de620_dev = de620_probe(-1); + if (IS_ERR(de620_dev)) + return PTR_ERR(de620_dev); return 0; } void cleanup_module(void) { - unregister_netdev(&de620_dev); - release_region(de620_dev.base_addr, 3); + unregister_netdev(de620_dev); + release_region(de620_dev->base_addr, 3); + free_netdev(de620_dev); } #endif /* MODULE */ MODULE_LICENSE("GPL"); diff -Nru a/drivers/net/declance.c b/drivers/net/declance.c --- a/drivers/net/declance.c Thu Jan 22 18:59:25 2004 +++ b/drivers/net/declance.c Thu Jan 22 18:59:25 2004 @@ -1039,13 +1039,13 @@ if (dec_lance_debug && version_printed++ == 0) printk(version); - dev = init_etherdev(NULL, sizeof(struct lance_private)); + dev = alloc_etherdev(sizeof(struct lance_private)); if (!dev) return -ENOMEM; SET_MODULE_OWNER(dev); /* - * init_etherdev ensures the data structures used by the LANCE + * alloc_etherdev ensures the data structures used by the LANCE * are aligned. */ lp = (struct lance_private *) dev->priv; @@ -1188,9 +1188,6 @@ } } - lp->next = root_lance_dev; - root_lance_dev = dev; - /* Copy the ethernet address to the device structure, later to the * lance initialization block so the lance gets it every time it's * (re)initialized. @@ -1239,11 +1236,14 @@ init_timer(&lp->multicast_timer); lp->multicast_timer.data = (unsigned long) dev; lp->multicast_timer.function = &lance_set_multicast_retry; - + ret = register_netdev(dev); + if (ret) + goto err_out; + lp->next = root_lance_dev; + root_lance_dev = dev; return 0; err_out: - unregister_netdev(dev); free_netdev(dev); return ret; } @@ -1288,13 +1288,12 @@ while (root_lance_dev) { struct net_device *dev = root_lance_dev; struct lance_private *lp = (struct lance_private *)dev->priv; - + unregister_netdev(dev); #ifdef CONFIG_TC if (lp->slot >= 0) release_tc_card(lp->slot); #endif root_lance_dev = lp->next; - unregister_netdev(dev); free_netdev(dev); } } diff -Nru a/drivers/net/defxx.c b/drivers/net/defxx.c --- a/drivers/net/defxx.c Thu Jan 22 18:59:23 2004 +++ b/drivers/net/defxx.c Thu Jan 22 18:59:23 2004 @@ -491,7 +491,7 @@ err_out_region: release_region(ioaddr, pdev ? PFI_K_CSR_IO_LEN : PI_ESIC_K_CSR_IO_LEN); err_out: - kfree(dev); + free_netdev(dev); return err; } diff -Nru a/drivers/net/depca.c b/drivers/net/depca.c --- a/drivers/net/depca.c Thu Jan 22 18:59:25 2004 +++ b/drivers/net/depca.c Thu Jan 22 18:59:25 2004 @@ -681,8 +681,7 @@ lp->sh_mem = ioremap(mem_start, mem_len); if (lp->sh_mem == NULL) { printk(KERN_ERR "depca: cannot remap ISA memory, aborting\n"); - release_mem_region (mem_start, mem_len); - goto out_priv; + goto out1; } lp->mem_start = mem_start; @@ -771,7 +770,7 @@ status = -ENXIO; if (!irqnum) { printk(" and failed to detect IRQ line.\n"); - goto out_priv; + goto out2; } else { for (dev->irq = 0, i = 0; (depca_irq[i]) && (!dev->irq); i++) if (irqnum == depca_irq[i]) { @@ -781,7 +780,7 @@ if (!dev->irq) { printk(" but incorrect IRQ line detected.\n"); - return -ENXIO; + goto out2; } } } else { @@ -807,11 +806,14 @@ device->driver_data = dev; SET_NETDEV_DEV (dev, device); - register_netdev (dev); - return 0; - - out_priv: - + status = register_netdev(dev); + if (status == 0) + return 0; +out2: + iounmap(lp->sh_mem); +out1: + release_mem_region (mem_start, mem_len); +out_priv: return status; } diff -Nru a/drivers/net/dgrs.c b/drivers/net/dgrs.c --- a/drivers/net/dgrs.c Thu Jan 22 18:59:23 2004 +++ b/drivers/net/dgrs.c Thu Jan 22 18:59:23 2004 @@ -121,11 +121,22 @@ #include "dgrs_asstruct.h" #include "dgrs_bcomm.h" +#ifdef CONFIG_PCI static struct pci_device_id dgrs_pci_tbl[] = { { SE6_PCI_VENDOR_ID, SE6_PCI_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID, }, { } /* Terminating entry */ }; MODULE_DEVICE_TABLE(pci, dgrs_pci_tbl); +#endif + +#ifdef CONFIG_EISA +static struct eisa_device_id dgrs_eisa_tbl[] = { + { "DBI0A01" }, + { } +}; +MODULE_DEVICE_TABLE(eisa, dgrs_eisa_tbl); +#endif + MODULE_LICENSE("GPL"); @@ -179,11 +190,6 @@ static int dgrs_nicmode; /* - * Chain of device structures - */ -static struct net_device *dgrs_root_dev; - -/* * Private per-board data structure (dev->priv) */ typedef struct @@ -191,7 +197,6 @@ /* * Stuff for generic ethercard I/F */ - struct net_device *next_dev; struct net_device_stats stats; /* @@ -1187,7 +1192,7 @@ priv->intrcnt = 0; for (i = jiffies + 2*HZ + HZ/2; time_after(i, jiffies); ) { - barrier(); /* gcc 2.95 needs this */ + cpu_relax(); if (priv->intrcnt >= 2) break; } @@ -1200,16 +1205,6 @@ } /* - * Register the /proc/ioports information... - */ - if (!request_region(dev->base_addr, 256, "RightSwitch")) { - printk(KERN_ERR "%s: io 0x%3lX, which is busy.\n", dev->name, - dev->base_addr); - rc = -EBUSY; - goto err_free_irq; - } - - /* * Entry points... */ dev->open = &dgrs_open; @@ -1242,22 +1237,23 @@ return (0); } -static int __init +static struct net_device * __init dgrs_found_device( int io, ulong mem, int irq, ulong plxreg, - ulong plxdma + ulong plxdma, + struct device *pdev ) { - DGRS_PRIV *priv; - struct net_device *dev, *aux; - int i, ret; + DGRS_PRIV *priv; + struct net_device *dev; + int i, ret = -ENOMEM; dev = alloc_etherdev(sizeof(DGRS_PRIV)); if (!dev) - return -ENOMEM; + goto err0; priv = (DGRS_PRIV *)dev->priv; @@ -1272,19 +1268,19 @@ priv->chan = 1; priv->devtbl[0] = dev; - dev->init = dgrs_probe1; SET_MODULE_OWNER(dev); - - if (register_netdev(dev) != 0) { - free_netdev(dev); - return -EIO; - } - - priv->next_dev = dgrs_root_dev; - dgrs_root_dev = dev; + SET_NETDEV_DEV(dev, pdev); + + ret = dgrs_probe1(dev); + if (ret) + goto err1; + + ret = register_netdev(dev); + if (ret) + goto err2; if ( !dgrs_nicmode ) - return (0); /* Switch mode, we are done */ + return dev; /* Switch mode, we are done */ /* * Operating card as N separate NICs @@ -1302,8 +1298,7 @@ if (!devN) goto fail; - /* Make it an exact copy of dev[0]... */ - *devN = *dev; + /* Don't copy the network device structure! */ /* copy the priv structure of dev[0] */ privN = (DGRS_PRIV *)devN->priv; @@ -1316,123 +1311,212 @@ devN->irq = 0; /* ... and base MAC address off address of 1st port */ devN->dev_addr[5] += i; - /* ... choose a new name */ - strncpy(devN->name, "eth%d", IFNAMSIZ); - devN->init = dgrs_initclone; + + ret = dgrs_initclone(devN); + if (ret) + goto fail; + SET_MODULE_OWNER(devN); + SET_NETDEV_DEV(dev, pdev); - ret = -EIO; - if (register_netdev(devN)) { + ret = register_netdev(devN); + if (ret) { free_netdev(devN); goto fail; } privN->chan = i+1; priv->devtbl[i] = devN; - privN->next_dev = dgrs_root_dev; - dgrs_root_dev = devN; } - return 0; -fail: aux = priv->next_dev; - while (dgrs_root_dev != aux) { - struct net_device *d = dgrs_root_dev; - - dgrs_root_dev = ((DGRS_PRIV *)d->priv)->next_dev; + return dev; + + fail: + while (i >= 0) { + struct net_device *d = priv->devtbl[i--]; unregister_netdev(d); free_netdev(d); } - return ret; + + err2: + free_irq(dev->irq, dev); + err1: + free_netdev(dev); + err0: + return ERR_PTR(ret); } -/* - * Scan for all boards - */ -static int is2iv[8] __initdata = { 0, 3, 5, 7, 10, 11, 12, 15 }; +static void __devexit dgrs_remove(struct net_device *dev) +{ + DGRS_PRIV *priv = dev->priv; + int i; + + unregister_netdev(dev); + + for (i = 1; i < priv->nports; ++i) { + struct net_device *d = priv->devtbl[i]; + if (d) { + unregister_netdev(d); + free_netdev(d); + } + } + + proc_reset(priv->devtbl[0], 1); -static int __init dgrs_scan(void) + if (priv->vmem) + iounmap(priv->vmem); + if (priv->vplxdma) + iounmap((uchar *) priv->vplxdma); + + if (dev->irq) + free_irq(dev->irq, dev); + + for (i = 1; i < priv->nports; ++i) { + if (priv->devtbl[i]) + unregister_netdev(priv->devtbl[i]); + } +} + +#ifdef CONFIG_PCI +static int __init dgrs_pci_probe(struct pci_dev *pdev, + const struct pci_device_id *ent) { - int cards_found = 0; + struct net_device *dev; + int err; uint io; uint mem; uint irq; uint plxreg; uint plxdma; - struct pci_dev *pdev = NULL; /* - * First, check for PCI boards - */ - while ((pdev = pci_find_device(SE6_PCI_VENDOR_ID, SE6_PCI_DEVICE_ID, pdev)) != NULL) - { - /* - * Get and check the bus-master and latency values. - * Some PCI BIOSes fail to set the master-enable bit, - * and the latency timer must be set to the maximum - * value to avoid data corruption that occurs when the - * timer expires during a transfer. Yes, it's a bug. - */ - if (pci_enable_device(pdev)) - continue; - pci_set_master(pdev); - - plxreg = pci_resource_start (pdev, 0); - io = pci_resource_start (pdev, 1); - mem = pci_resource_start (pdev, 2); - pci_read_config_dword(pdev, 0x30, &plxdma); - irq = pdev->irq; - plxdma &= ~15; + * Get and check the bus-master and latency values. + * Some PCI BIOSes fail to set the master-enable bit, + * and the latency timer must be set to the maximum + * value to avoid data corruption that occurs when the + * timer expires during a transfer. Yes, it's a bug. + */ + err = pci_enable_device(pdev); + if (err) + return err; + err = pci_request_regions(pdev, "RightSwitch"); + if (err) + return err; + + pci_set_master(pdev); + + plxreg = pci_resource_start (pdev, 0); + io = pci_resource_start (pdev, 1); + mem = pci_resource_start (pdev, 2); + pci_read_config_dword(pdev, 0x30, &plxdma); + irq = pdev->irq; + plxdma &= ~15; + + /* + * On some BIOSES, the PLX "expansion rom" (used for DMA) + * address comes up as "0". This is probably because + * the BIOS doesn't see a valid 55 AA ROM signature at + * the "ROM" start and zeroes the address. To get + * around this problem the SE-6 is configured to ask + * for 4 MB of space for the dual port memory. We then + * must set its range back to 2 MB, and use the upper + * half for DMA register access + */ + OUTL(io + PLX_SPACE0_RANGE, 0xFFE00000L); + if (plxdma == 0) + plxdma = mem + (2048L * 1024L); + pci_write_config_dword(pdev, 0x30, plxdma + 1); + pci_read_config_dword(pdev, 0x30, &plxdma); + plxdma &= ~15; + + dev = dgrs_found_device(io, mem, irq, plxreg, plxdma, &pdev->dev); + if (IS_ERR(dev)) { + pci_release_regions(pdev); + return PTR_ERR(dev); + } - /* - * On some BIOSES, the PLX "expansion rom" (used for DMA) - * address comes up as "0". This is probably because - * the BIOS doesn't see a valid 55 AA ROM signature at - * the "ROM" start and zeroes the address. To get - * around this problem the SE-6 is configured to ask - * for 4 MB of space for the dual port memory. We then - * must set its range back to 2 MB, and use the upper - * half for DMA register access - */ - OUTL(io + PLX_SPACE0_RANGE, 0xFFE00000L); - if (plxdma == 0) - plxdma = mem + (2048L * 1024L); - pci_write_config_dword(pdev, 0x30, plxdma + 1); - pci_read_config_dword(pdev, 0x30, &plxdma); - plxdma &= ~15; + pci_set_drvdata(pdev, dev); + return 0; +} - dgrs_found_device(io, mem, irq, plxreg, plxdma); +static void __devexit dgrs_pci_remove(struct pci_dev *pdev) +{ + struct net_device *dev = pci_get_drvdata(pdev); - cards_found++; - } + dgrs_remove(dev); + pci_release_regions(pdev); + free_netdev(dev); +} - /* - * Second, check for EISA boards - */ - if (EISA_bus) - { - for (io = 0x1000; io < 0x9000; io += 0x1000) - { - if (inb(io+ES4H_MANUFmsb) != 0x10 - || inb(io+ES4H_MANUFlsb) != 0x49 - || inb(io+ES4H_PRODUCT) != ES4H_PRODUCT_CODE) - continue; +static struct pci_driver dgrs_pci_driver = { + .name = "dgrs", + .id_table = dgrs_pci_tbl, + .probe = dgrs_pci_probe, + .remove = __devexit_p(dgrs_pci_remove), +}; +#endif + + +#ifdef CONFIG_EISA +static int is2iv[8] __initdata = { 0, 3, 5, 7, 10, 11, 12, 15 }; - if ( ! (inb(io+ES4H_EC) & ES4H_EC_ENABLE) ) - continue; /* Not EISA configured */ +static int __init dgrs_eisa_probe (struct device *gendev) +{ + struct net_device *dev; + struct eisa_device *edev = to_eisa_device(gendev); + uint io = edev->base_addr; + uint mem; + uint irq; + int rc = -ENODEV; /* Not EISA configured */ + + if (!request_region(io, 256, "RightSwitch")) { + printk(KERN_ERR "%s: io 0x%3lX, which is busy.\n", dev->name, + dev->base_addr); + return -EBUSY; + } - mem = (inb(io+ES4H_AS_31_24) << 24) - + (inb(io+ES4H_AS_23_16) << 16); + if ( ! (inb(io+ES4H_EC) & ES4H_EC_ENABLE) ) + goto err_out; - irq = is2iv[ inb(io+ES4H_IS) & ES4H_IS_INTMASK ]; + mem = (inb(io+ES4H_AS_31_24) << 24) + + (inb(io+ES4H_AS_23_16) << 16); - dgrs_found_device(io, mem, irq, 0L, 0L); + irq = is2iv[ inb(io+ES4H_IS) & ES4H_IS_INTMASK ]; - ++cards_found; - } + dev = dgrs_found_device(io, mem, irq, 0L, 0L, gendev); + if (IS_ERR(dev)) { + rc = PTR_ERR(dev); + goto err_out; } - return cards_found; + gendev->driver_data = dev; + return 0; + err_out: + release_region(io, 256); + return rc; +} + +static int __devexit dgrs_eisa_remove(struct device *gendev) +{ + struct net_device *dev = gendev->driver_data; + + dgrs_remove(dev); + + release_region(dev->base_addr, 256); + + free_netdev(dev); + return 0; } +static struct eisa_driver dgrs_eisa_driver = { + .id_table = dgrs_eisa_tbl, + .driver = { + .name = "dgrs", + .probe = dgrs_eisa_probe, + .remove = __devexit_p(dgrs_eisa_remove), + } +}; +#endif + /* * Variables that can be overriden from module command line */ @@ -1459,8 +1543,8 @@ static int __init dgrs_init_module (void) { - int cards_found; int i; + int eisacount = 0, pcicount = 0; /* * Command line variable overrides @@ -1501,38 +1585,27 @@ /* * Find and configure all the cards */ - dgrs_root_dev = NULL; - cards_found = dgrs_scan(); - - return cards_found ? 0 : -ENODEV; +#ifdef CONFIG_EISA + eisacount = eisa_driver_register(&dgrs_eisa_driver); + if (eisacount < 0) + return eisacount; +#endif +#ifdef CONFIG_PCI + pcicount = pci_register_driver(&dgrs_pci_driver); + if (pcicount < 0) + return pcicount; +#endif + return (eisacount + pcicount) == 0 ? -ENODEV : 0; } static void __exit dgrs_cleanup_module (void) { - while (dgrs_root_dev) - { - struct net_device *next_dev; - DGRS_PRIV *priv; - - priv = (DGRS_PRIV *) dgrs_root_dev->priv; - next_dev = priv->next_dev; - unregister_netdev(dgrs_root_dev); - - proc_reset(priv->devtbl[0], 1); - - if (priv->vmem) - iounmap(priv->vmem); - if (priv->vplxdma) - iounmap((uchar *) priv->vplxdma); - - release_region(dgrs_root_dev->base_addr, 256); - - if (dgrs_root_dev->irq) - free_irq(dgrs_root_dev->irq, dgrs_root_dev); - - free_netdev(dgrs_root_dev); - dgrs_root_dev = next_dev; - } +#ifdef CONFIG_EISA + eisa_driver_unregister (&dgrs_eisa_driver); +#endif +#ifdef CONFIG_PCI + pci_unregister_driver (&dgrs_pci_driver); +#endif } module_init(dgrs_init_module); diff -Nru a/drivers/net/dummy.c b/drivers/net/dummy.c --- a/drivers/net/dummy.c Thu Jan 22 18:59:25 2004 +++ b/drivers/net/dummy.c Thu Jan 22 18:59:25 2004 @@ -103,7 +103,7 @@ return -ENOMEM; if ((err = register_netdev(dev_dummy))) { - kfree(dev_dummy); + free_netdev(dev_dummy); dev_dummy = NULL; } else { dummies[index] = dev_dummy; diff -Nru a/drivers/net/e100/LICENSE b/drivers/net/e100/LICENSE --- a/drivers/net/e100/LICENSE Thu Jan 22 18:59:26 2004 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,339 +0,0 @@ - -"This software program is licensed subject to the GNU General Public License -(GPL). Version 2, June 1991, available at -" - -GNU General Public License - -Version 2, June 1991 - -Copyright (C) 1989, 1991 Free Software Foundation, Inc. -59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - -Everyone is permitted to copy and distribute verbatim copies of this license -document, but changing it is not allowed. - -Preamble - -The licenses for most software are designed to take away your freedom to -share and change it. By contrast, the GNU General Public License is intended -to guarantee your freedom to share and change free software--to make sure -the software is free for all its users. This General Public License applies -to most of the Free Software Foundation's software and to any other program -whose authors commit to using it. (Some other Free Software Foundation -software is covered by the GNU Library General Public License instead.) You -can apply it to your programs, too. - -When we speak of free software, we are referring to freedom, not price. Our -General Public Licenses are designed to make sure that you have the freedom -to distribute copies of free software (and charge for this service if you -wish), that you receive source code or can get it if you want it, that you -can change the software or use pieces of it in new free programs; and that -you know you can do these things. - -To protect your rights, we need to make restrictions that forbid anyone to -deny you these rights or to ask you to surrender the rights. These -restrictions translate to certain responsibilities for you if you distribute -copies of the software, or if you modify it. - -For example, if you distribute copies of such a program, whether gratis or -for a fee, you must give the recipients all the rights that you have. You -must make sure that they, too, receive or can get the source code. And you -must show them these terms so they know their rights. - -We protect your rights with two steps: (1) copyright the software, and (2) -offer you this license which gives you legal permission to copy, distribute -and/or modify the software. - -Also, for each author's protection and ours, we want to make certain that -everyone understands that there is no warranty for this free software. If -the software is modified by someone else and passed on, we want its -recipients to know that what they have is not the original, so that any -problems introduced by others will not reflect on the original authors' -reputations. - -Finally, any free program is threatened constantly by software patents. We -wish to avoid the danger that redistributors of a free program will -individually obtain patent licenses, in effect making the program -proprietary. To prevent this, we have made it clear that any patent must be -licensed for everyone's free use or not licensed at all. - -The precise terms and conditions for copying, distribution and modification -follow. - -TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - -0. This License applies to any program or other work which contains a notice - placed by the copyright holder saying it may be distributed under the - terms of this General Public License. The "Program", below, refers to any - such program or work, and a "work based on the Program" means either the - Program or any derivative work under copyright law: that is to say, a - work containing the Program or a portion of it, either verbatim or with - modifications and/or translated into another language. (Hereinafter, - translation is included without limitation in the term "modification".) - Each licensee is addressed as "you". - - Activities other than copying, distribution and modification are not - covered by this License; they are outside its scope. The act of running - the Program is not restricted, and the output from the Program is covered - only if its contents constitute a work based on the Program (independent - of having been made by running the Program). Whether that is true depends - on what the Program does. - -1. You may copy and distribute verbatim copies of the Program's source code - as you receive it, in any medium, provided that you conspicuously and - appropriately publish on each copy an appropriate copyright notice and - disclaimer of warranty; keep intact all the notices that refer to this - License and to the absence of any warranty; and give any other recipients - of the Program a copy of this License along with the Program. - - You may charge a fee for the physical act of transferring a copy, and you - may at your option offer warranty protection in exchange for a fee. - -2. You may modify your copy or copies of the Program or any portion of it, - thus forming a work based on the Program, and copy and distribute such - modifications or work under the terms of Section 1 above, provided that - you also meet all of these conditions: - - * a) You must cause the modified files to carry prominent notices stating - that you changed the files and the date of any change. - - * b) You must cause any work that you distribute or publish, that in - whole or in part contains or is derived from the Program or any part - thereof, to be licensed as a whole at no charge to all third parties - under the terms of this License. - - * c) If the modified program normally reads commands interactively when - run, you must cause it, when started running for such interactive - use in the most ordinary way, to print or display an announcement - including an appropriate copyright notice and a notice that there is - no warranty (or else, saying that you provide a warranty) and that - users may redistribute the program under these conditions, and - telling the user how to view a copy of this License. (Exception: if - the Program itself is interactive but does not normally print such - an announcement, your work based on the Program is not required to - print an announcement.) - - These requirements apply to the modified work as a whole. If identifiable - sections of that work are not derived from the Program, and can be - reasonably considered independent and separate works in themselves, then - this License, and its terms, do not apply to those sections when you - distribute them as separate works. But when you distribute the same - sections as part of a whole which is a work based on the Program, the - distribution of the whole must be on the terms of this License, whose - permissions for other licensees extend to the entire whole, and thus to - each and every part regardless of who wrote it. - - Thus, it is not the intent of this section to claim rights or contest - your rights to work written entirely by you; rather, the intent is to - exercise the right to control the distribution of derivative or - collective works based on the Program. - - In addition, mere aggregation of another work not based on the Program - with the Program (or with a work based on the Program) on a volume of a - storage or distribution medium does not bring the other work under the - scope of this License. - -3. You may copy and distribute the Program (or a work based on it, under - Section 2) in object code or executable form under the terms of Sections - 1 and 2 above provided that you also do one of the following: - - * a) Accompany it with the complete corresponding machine-readable source - code, which must be distributed under the terms of Sections 1 and 2 - above on a medium customarily used for software interchange; or, - - * b) Accompany it with a written offer, valid for at least three years, - to give any third party, for a charge no more than your cost of - physically performing source distribution, a complete machine- - readable copy of the corresponding source code, to be distributed - under the terms of Sections 1 and 2 above on a medium customarily - used for software interchange; or, - - * c) Accompany it with the information you received as to the offer to - distribute corresponding source code. (This alternative is allowed - only for noncommercial distribution and only if you received the - program in object code or executable form with such an offer, in - accord with Subsection b above.) - - The source code for a work means the preferred form of the work for - making modifications to it. For an executable work, complete source code - means all the source code for all modules it contains, plus any - associated interface definition files, plus the scripts used to control - compilation and installation of the executable. However, as a special - exception, the source code distributed need not include anything that is - normally distributed (in either source or binary form) with the major - components (compiler, kernel, and so on) of the operating system on which - the executable runs, unless that component itself accompanies the - executable. - - If distribution of executable or object code is made by offering access - to copy from a designated place, then offering equivalent access to copy - the source code from the same place counts as distribution of the source - code, even though third parties are not compelled to copy the source - along with the object code. - -4. You may not copy, modify, sublicense, or distribute the Program except as - expressly provided under this License. Any attempt otherwise to copy, - modify, sublicense or distribute the Program is void, and will - automatically terminate your rights under this License. However, parties - who have received copies, or rights, from you under this License will not - have their licenses terminated so long as such parties remain in full - compliance. - -5. You are not required to accept this License, since you have not signed - it. However, nothing else grants you permission to modify or distribute - the Program or its derivative works. These actions are prohibited by law - if you do not accept this License. Therefore, by modifying or - distributing the Program (or any work based on the Program), you - indicate your acceptance of this License to do so, and all its terms and - conditions for copying, distributing or modifying the Program or works - based on it. - -6. Each time you redistribute the Program (or any work based on the - Program), the recipient automatically receives a license from the - original licensor to copy, distribute or modify the Program subject to - these terms and conditions. You may not impose any further restrictions - on the recipients' exercise of the rights granted herein. You are not - responsible for enforcing compliance by third parties to this License. - -7. If, as a consequence of a court judgment or allegation of patent - infringement or for any other reason (not limited to patent issues), - conditions are imposed on you (whether by court order, agreement or - otherwise) that contradict the conditions of this License, they do not - excuse you from the conditions of this License. If you cannot distribute - so as to satisfy simultaneously your obligations under this License and - any other pertinent obligations, then as a consequence you may not - distribute the Program at all. For example, if a patent license would - not permit royalty-free redistribution of the Program by all those who - receive copies directly or indirectly through you, then the only way you - could satisfy both it and this License would be to refrain entirely from - distribution of the Program. - - If any portion of this section is held invalid or unenforceable under any - particular circumstance, the balance of the section is intended to apply - and the section as a whole is intended to apply in other circumstances. - - It is not the purpose of this section to induce you to infringe any - patents or other property right claims or to contest validity of any - such claims; this section has the sole purpose of protecting the - integrity of the free software distribution system, which is implemented - by public license practices. Many people have made generous contributions - to the wide range of software distributed through that system in - reliance on consistent application of that system; it is up to the - author/donor to decide if he or she is willing to distribute software - through any other system and a licensee cannot impose that choice. - - This section is intended to make thoroughly clear what is believed to be - a consequence of the rest of this License. - -8. If the distribution and/or use of the Program is restricted in certain - countries either by patents or by copyrighted interfaces, the original - copyright holder who places the Program under this License may add an - explicit geographical distribution limitation excluding those countries, - so that distribution is permitted only in or among countries not thus - excluded. In such case, this License incorporates the limitation as if - written in the body of this License. - -9. The Free Software Foundation may publish revised and/or new versions of - the General Public License from time to time. Such new versions will be - similar in spirit to the present version, but may differ in detail to - address new problems or concerns. - - Each version is given a distinguishing version number. If the Program - specifies a version number of this License which applies to it and "any - later version", you have the option of following the terms and - conditions either of that version or of any later version published by - the Free Software Foundation. If the Program does not specify a version - number of this License, you may choose any version ever published by the - Free Software Foundation. - -10. If you wish to incorporate parts of the Program into other free programs - whose distribution conditions are different, write to the author to ask - for permission. For software which is copyrighted by the Free Software - Foundation, write to the Free Software Foundation; we sometimes make - exceptions for this. Our decision will be guided by the two goals of - preserving the free status of all derivatives of our free software and - of promoting the sharing and reuse of software generally. - - NO WARRANTY - -11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY - FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN - OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES - PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER - EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE - ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH - YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL - NECESSARY SERVICING, REPAIR OR CORRECTION. - -12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING - WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR - REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR - DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL - DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM - (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED - INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF - THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR - OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. - -END OF TERMS AND CONDITIONS - -How to Apply These Terms to Your New Programs - -If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it free -software which everyone can redistribute and change under these terms. - -To do so, attach the following notices to the program. It is safest to -attach them to the start of each source file to most effectively convey the -exclusion of warranty; and each file should have at least the "copyright" -line and a pointer to where the full notice is found. - -one line to give the program's name and an idea of what it does. -Copyright (C) yyyy name of author - -This program is free software; you can redistribute it and/or modify it -under the terms of the GNU General Public License as published by the Free -Software Foundation; either version 2 of the License, or (at your option) -any later version. - -This program is distributed in the hope that it will be useful, but WITHOUT -ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -more details. - -You should have received a copy of the GNU General Public License along with -this program; if not, write to the Free Software Foundation, Inc., 59 -Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -Also add information on how to contact you by electronic and paper mail. - -If the program is interactive, make it output a short notice like this when -it starts in an interactive mode: - -Gnomovision version 69, Copyright (C) year name of author Gnomovision comes -with ABSOLUTELY NO WARRANTY; for details type 'show w'. This is free -software, and you are welcome to redistribute it under certain conditions; -type 'show c' for details. - -The hypothetical commands 'show w' and 'show c' should show the appropriate -parts of the General Public License. Of course, the commands you use may be -called something other than 'show w' and 'show c'; they could even be -mouse-clicks or menu items--whatever suits your program. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the program, if -necessary. Here is a sample; alter the names: - -Yoyodyne, Inc., hereby disclaims all copyright interest in the program -'Gnomovision' (which makes passes at compilers) written by James Hacker. - -signature of Ty Coon, 1 April 1989 -Ty Coon, President of Vice - -This General Public License does not permit incorporating your program into -proprietary programs. If your program is a subroutine library, you may -consider it more useful to permit linking proprietary applications with the -library. If this is what you want to do, use the GNU Library General Public -License instead of this License. diff -Nru a/drivers/net/e100/Makefile b/drivers/net/e100/Makefile --- a/drivers/net/e100/Makefile Thu Jan 22 18:59:26 2004 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,8 +0,0 @@ -# -# Makefile for the Intel's E100 ethernet driver -# - -obj-$(CONFIG_E100) += e100.o - -e100-objs := e100_main.o e100_config.o e100_phy.o \ - e100_eeprom.o e100_test.o diff -Nru a/drivers/net/e100/e100.h b/drivers/net/e100/e100.h --- a/drivers/net/e100/e100.h Thu Jan 22 18:59:24 2004 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,999 +0,0 @@ -/******************************************************************************* - - - Copyright(c) 1999 - 2003 Intel Corporation. All rights reserved. - - This program is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by the Free - Software Foundation; either version 2 of the License, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - this program; if not, write to the Free Software Foundation, Inc., 59 - Temple Place - Suite 330, Boston, MA 02111-1307, USA. - - The full GNU General Public License is included in this distribution in the - file called LICENSE. - - Contact Information: - Linux NICS - Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 -*******************************************************************************/ - -#ifndef _E100_INC_ -#define _E100_INC_ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#define E100_CABLE_UNKNOWN 0 -#define E100_CABLE_OK 1 -#define E100_CABLE_OPEN_NEAR 2 /* Open Circuit Near End */ -#define E100_CABLE_OPEN_FAR 3 /* Open Circuit Far End */ -#define E100_CABLE_SHORT_NEAR 4 /* Short Circuit Near End */ -#define E100_CABLE_SHORT_FAR 5 /* Short Circuit Far End */ - -#define E100_REGS_LEN 2 -/* - * Configure parameters for buffers per controller. - * If the machine this is being used on is a faster machine (i.e. > 150MHz) - * and running on a 10MBS network then more queueing of data occurs. This - * may indicate the some of the numbers below should be adjusted. Here are - * some typical numbers: - * MAX_TCB 64 - * MAX_RFD 64 - * The default numbers give work well on most systems tests so no real - * adjustments really need to take place. Also, if the machine is connected - * to a 100MBS network the numbers described above can be lowered from the - * defaults as considerably less data will be queued. - */ - -#define TX_FRAME_CNT 8 /* consecutive transmit frames per interrupt */ -/* TX_FRAME_CNT must be less than MAX_TCB */ - -#define E100_DEFAULT_TCB 64 -#define E100_MIN_TCB 2*TX_FRAME_CNT + 3 /* make room for at least 2 interrupts */ -#define E100_MAX_TCB 1024 - -#define E100_DEFAULT_RFD 64 -#define E100_MIN_RFD 8 -#define E100_MAX_RFD 1024 - -#define E100_DEFAULT_XSUM true -#define E100_DEFAULT_BER ZLOCK_MAX_ERRORS -#define E100_DEFAULT_SPEED_DUPLEX 0 -#define E100_DEFAULT_FC 0 -#define E100_DEFAULT_IFS true -#define E100_DEFAULT_UCODE true - -#define TX_THRSHLD 8 - -/* IFS parameters */ -#define MIN_NUMBER_OF_TRANSMITS_100 1000 -#define MIN_NUMBER_OF_TRANSMITS_10 100 - -#define E100_MAX_NIC 16 - -#define E100_MAX_SCB_WAIT 100 /* Max udelays in wait_scb */ -#define E100_MAX_CU_IDLE_WAIT 50 /* Max udelays in wait_cus_idle */ - -/* HWI feature related constant */ -#define HWI_REGISTER_GRANULARITY 80 /* register granularity = 80 Cm */ -#define HWI_NEAR_END_BOUNDARY 1000 /* Near end is defined as < 10 meters */ - -/* CPUSAVER_BUNDLE_MAX: Sets the maximum number of frames that will be bundled. - * In some situations, such as the TCP windowing algorithm, it may be - * better to limit the growth of the bundle size than let it go as - * high as it can, because that could cause too much added latency. - * The default is six, because this is the number of packets in the - * default TCP window size. A value of 1 would make CPUSaver indicate - * an interrupt for every frame received. If you do not want to put - * a limit on the bundle size, set this value to xFFFF. - */ -#define E100_DEFAULT_CPUSAVER_BUNDLE_MAX 6 -#define E100_DEFAULT_CPUSAVER_INTERRUPT_DELAY 0x600 -#define E100_DEFAULT_BUNDLE_SMALL_FR false - -/* end of configurables */ - -/* ====================================================================== */ -/* hw */ -/* ====================================================================== */ - -/* timeout for command completion */ -#define E100_CMD_WAIT 100 /* iterations */ - -struct driver_stats { - struct net_device_stats net_stats; - - unsigned long tx_late_col; - unsigned long tx_ok_defrd; - unsigned long tx_one_retry; - unsigned long tx_mt_one_retry; - unsigned long rcv_cdt_frames; - unsigned long xmt_fc_pkts; - unsigned long rcv_fc_pkts; - unsigned long rcv_fc_unsupported; - unsigned long xmt_tco_pkts; - unsigned long rcv_tco_pkts; - unsigned long rx_intr_pkts; -}; - -/* TODO: kill me when we can do C99 */ -#define false (0) -#define true (1) - -/* Changed for 82558 and 82559 enhancements */ -/* defines for 82558/9 flow control CSR values */ -#define DFLT_FC_THLD 0x00 /* Rx FIFO threshold of 0.5KB free */ -#define DFLT_FC_CMD 0x00 /* FC Command in CSR */ - -/* ====================================================================== */ -/* equates */ -/* ====================================================================== */ - -/* - * These are general purpose defines - */ - -/* Bit Mask definitions */ -#define BIT_0 0x0001 -#define BIT_1 0x0002 -#define BIT_2 0x0004 -#define BIT_3 0x0008 -#define BIT_4 0x0010 -#define BIT_5 0x0020 -#define BIT_6 0x0040 -#define BIT_7 0x0080 -#define BIT_8 0x0100 -#define BIT_9 0x0200 -#define BIT_10 0x0400 -#define BIT_11 0x0800 -#define BIT_12 0x1000 -#define BIT_13 0x2000 -#define BIT_14 0x4000 -#define BIT_15 0x8000 -#define BIT_28 0x10000000 - -#define BIT_0_2 0x0007 -#define BIT_0_3 0x000F -#define BIT_0_4 0x001F -#define BIT_0_5 0x003F -#define BIT_0_6 0x007F -#define BIT_0_7 0x00FF -#define BIT_0_8 0x01FF -#define BIT_0_13 0x3FFF -#define BIT_0_15 0xFFFF -#define BIT_1_2 0x0006 -#define BIT_1_3 0x000E -#define BIT_2_5 0x003C -#define BIT_3_4 0x0018 -#define BIT_4_5 0x0030 -#define BIT_4_6 0x0070 -#define BIT_4_7 0x00F0 -#define BIT_5_7 0x00E0 -#define BIT_5_12 0x1FE0 -#define BIT_5_15 0xFFE0 -#define BIT_6_7 0x00c0 -#define BIT_7_11 0x0F80 -#define BIT_8_10 0x0700 -#define BIT_9_13 0x3E00 -#define BIT_12_15 0xF000 -#define BIT_8_15 0xFF00 - -#define BIT_16_20 0x001F0000 -#define BIT_21_25 0x03E00000 -#define BIT_26_27 0x0C000000 - -/* Transmit Threshold related constants */ -#define DEFAULT_TX_PER_UNDERRUN 20000 - -#define MAX_MULTICAST_ADDRS 64 -#define MAX_FILTER 16 - -#define FULL_DUPLEX 2 -#define HALF_DUPLEX 1 - -/* - * These defines are specific to the 82557 - */ - -/* E100 PORT functions -- lower 4 bits */ -#define PORT_SOFTWARE_RESET 0 -#define PORT_SELFTEST 1 -#define PORT_SELECTIVE_RESET 2 -#define PORT_DUMP 3 - -/* SCB Status Word bit definitions */ -/* Interrupt status/ack fields */ -/* ER and FCP interrupts for 82558 masks */ -#define SCB_STATUS_ACK_MASK BIT_8_15 /* Status Mask */ -#define SCB_STATUS_ACK_CX BIT_15 /* CU Completed Action Cmd */ -#define SCB_STATUS_ACK_FR BIT_14 /* RU Received A Frame */ -#define SCB_STATUS_ACK_CNA BIT_13 /* CU Became Inactive (IDLE) */ -#define SCB_STATUS_ACK_RNR BIT_12 /* RU Became Not Ready */ -#define SCB_STATUS_ACK_MDI BIT_11 /* MDI read or write done */ -#define SCB_STATUS_ACK_SWI BIT_10 /* S/W generated interrupt */ -#define SCB_STATUS_ACK_ER BIT_9 /* Early Receive */ -#define SCB_STATUS_ACK_FCP BIT_8 /* Flow Control Pause */ - -/*- CUS Fields */ -#define SCB_CUS_MASK (BIT_6 | BIT_7) /* CUS 2-bit Mask */ -#define SCB_CUS_IDLE 0 /* CU Idle */ -#define SCB_CUS_SUSPEND BIT_6 /* CU Suspended */ -#define SCB_CUS_ACTIVE BIT_7 /* CU Active */ - -/*- RUS Fields */ -#define SCB_RUS_IDLE 0 /* RU Idle */ -#define SCB_RUS_MASK BIT_2_5 /* RUS 3-bit Mask */ -#define SCB_RUS_SUSPEND BIT_2 /* RU Suspended */ -#define SCB_RUS_NO_RESOURCES BIT_3 /* RU Out Of Resources */ -#define SCB_RUS_READY BIT_4 /* RU Ready */ -#define SCB_RUS_SUSP_NO_RBDS (BIT_2 | BIT_5) /* RU No More RBDs */ -#define SCB_RUS_NO_RBDS (BIT_3 | BIT_5) /* RU No More RBDs */ -#define SCB_RUS_READY_NO_RBDS (BIT_4 | BIT_5) /* RU Ready, No RBDs */ - -/* SCB Command Word bit definitions */ -/*- CUC fields */ -/* Changing mask to 4 bits */ -#define SCB_CUC_MASK BIT_4_7 /* CUC 4-bit Mask */ -#define SCB_CUC_NOOP 0 -#define SCB_CUC_START BIT_4 /* CU Start */ -#define SCB_CUC_RESUME BIT_5 /* CU Resume */ -#define SCB_CUC_UNKNOWN BIT_7 /* CU unknown command */ -/* Changed for 82558 enhancements */ -#define SCB_CUC_STATIC_RESUME (BIT_5 | BIT_7) /* 82558/9 Static Resume */ -#define SCB_CUC_DUMP_ADDR BIT_6 /* CU Dump Counters Address */ -#define SCB_CUC_DUMP_STAT (BIT_4 | BIT_6) /* CU Dump stat. counters */ -#define SCB_CUC_LOAD_BASE (BIT_5 | BIT_6) /* Load the CU base */ -/* Below was defined as BIT_4_7 */ -#define SCB_CUC_DUMP_RST_STAT BIT_4_6 /* CU Dump & reset statistics cntrs */ - -/*- RUC fields */ -#define SCB_RUC_MASK BIT_0_2 /* RUC 3-bit Mask */ -#define SCB_RUC_START BIT_0 /* RU Start */ -#define SCB_RUC_RESUME BIT_1 /* RU Resume */ -#define SCB_RUC_ABORT BIT_2 /* RU Abort */ -#define SCB_RUC_LOAD_HDS (BIT_0 | BIT_2) /* Load RFD Header Data Size */ -#define SCB_RUC_LOAD_BASE (BIT_1 | BIT_2) /* Load the RU base */ -#define SCB_RUC_RBD_RESUME BIT_0_2 /* RBD resume */ - -/* Interrupt fields (assuming byte addressing) */ -#define SCB_INT_MASK BIT_0 /* Mask interrupts */ -#define SCB_SOFT_INT BIT_1 /* Generate a S/W interrupt */ -/* Specific Interrupt Mask Bits (upper byte of SCB Command word) */ -#define SCB_FCP_INT_MASK BIT_2 /* Flow Control Pause */ -#define SCB_ER_INT_MASK BIT_3 /* Early Receive */ -#define SCB_RNR_INT_MASK BIT_4 /* RU Not Ready */ -#define SCB_CNA_INT_MASK BIT_5 /* CU Not Active */ -#define SCB_FR_INT_MASK BIT_6 /* Frame Received */ -#define SCB_CX_INT_MASK BIT_7 /* CU eXecution w/ I-bit done */ -#define SCB_BACHELOR_INT_MASK BIT_2_7 /* 82558 interrupt mask bits */ - -#define SCB_GCR2_EEPROM_ACCESS_SEMAPHORE BIT_7 - -/* EEPROM bit definitions */ -/*- EEPROM control register bits */ -#define EEPROM_FLAG_ASF 0x8000 -#define EEPROM_FLAG_GCL 0x4000 - -#define EN_TRNF 0x10 /* Enable turnoff */ -#define EEDO 0x08 /* EEPROM data out */ -#define EEDI 0x04 /* EEPROM data in (set for writing data) */ -#define EECS 0x02 /* EEPROM chip select (1=hi, 0=lo) */ -#define EESK 0x01 /* EEPROM shift clock (1=hi, 0=lo) */ - -/*- EEPROM opcodes */ -#define EEPROM_READ_OPCODE 06 -#define EEPROM_WRITE_OPCODE 05 -#define EEPROM_ERASE_OPCODE 07 -#define EEPROM_EWEN_OPCODE 19 /* Erase/write enable */ -#define EEPROM_EWDS_OPCODE 16 /* Erase/write disable */ - -/*- EEPROM data locations */ -#define EEPROM_NODE_ADDRESS_BYTE_0 0 -#define EEPROM_COMPATIBILITY_WORD 3 -#define EEPROM_PWA_NO 8 -#define EEPROM_ID_WORD 0x0A -#define EEPROM_CONFIG_ASF 0x0D -#define EEPROM_SMBUS_ADDR 0x90 - -#define EEPROM_SUM 0xbaba - -// Zero Locking Algorithm definitions: -#define ZLOCK_ZERO_MASK 0x00F0 -#define ZLOCK_MAX_READS 50 -#define ZLOCK_SET_ZERO 0x2010 -#define ZLOCK_MAX_SLEEP 300 * HZ -#define ZLOCK_MAX_ERRORS 300 - -/* E100 Action Commands */ -#define CB_IA_ADDRESS 1 -#define CB_CONFIGURE 2 -#define CB_MULTICAST 3 -#define CB_TRANSMIT 4 -#define CB_LOAD_MICROCODE 5 -#define CB_LOAD_FILTER 8 -#define CB_MAX_NONTX_CMD 9 -#define CB_IPCB_TRANSMIT 9 - -/* Pre-defined Filter Bits */ -#define CB_FILTER_EL 0x80000000 -#define CB_FILTER_FIX 0x40000000 -#define CB_FILTER_ARP 0x08000000 -#define CB_FILTER_IA_MATCH 0x02000000 - -/* Command Block (CB) Field Definitions */ -/*- CB Command Word */ -#define CB_EL_BIT BIT_15 /* CB EL Bit */ -#define CB_S_BIT BIT_14 /* CB Suspend Bit */ -#define CB_I_BIT BIT_13 /* CB Interrupt Bit */ -#define CB_TX_SF_BIT BIT_3 /* TX CB Flexible Mode */ -#define CB_CMD_MASK BIT_0_3 /* CB 4-bit CMD Mask */ -#define CB_CID_DEFAULT (0x1f << 8) /* CB 5-bit CID (max value) */ - -/*- CB Status Word */ -#define CB_STATUS_MASK BIT_12_15 /* CB Status Mask (4-bits) */ -#define CB_STATUS_COMPLETE BIT_15 /* CB Complete Bit */ -#define CB_STATUS_OK BIT_13 /* CB OK Bit */ -#define CB_STATUS_VLAN BIT_12 /* CB Valn detected Bit */ -#define CB_STATUS_FAIL BIT_11 /* CB Fail (F) Bit */ - -/*misc command bits */ -#define CB_TX_EOF_BIT BIT_15 /* TX CB/TBD EOF Bit */ - -/* Config params */ -#define CB_CFIG_BYTE_COUNT 22 /* 22 config bytes */ -#define CB_CFIG_D102_BYTE_COUNT 10 - -/* Receive Frame Descriptor Fields */ - -/*- RFD Status Bits */ -#define RFD_RECEIVE_COLLISION BIT_0 /* Collision detected on Receive */ -#define RFD_IA_MATCH BIT_1 /* Indv Address Match Bit */ -#define RFD_RX_ERR BIT_4 /* RX_ERR pin on Phy was set */ -#define RFD_FRAME_TOO_SHORT BIT_7 /* Receive Frame Short */ -#define RFD_DMA_OVERRUN BIT_8 /* Receive DMA Overrun */ -#define RFD_NO_RESOURCES BIT_9 /* No Buffer Space */ -#define RFD_ALIGNMENT_ERROR BIT_10 /* Alignment Error */ -#define RFD_CRC_ERROR BIT_11 /* CRC Error */ -#define RFD_STATUS_OK BIT_13 /* RFD OK Bit */ -#define RFD_STATUS_COMPLETE BIT_15 /* RFD Complete Bit */ - -/*- RFD Command Bits*/ -#define RFD_EL_BIT BIT_15 /* RFD EL Bit */ -#define RFD_S_BIT BIT_14 /* RFD Suspend Bit */ -#define RFD_H_BIT BIT_4 /* Header RFD Bit */ -#define RFD_SF_BIT BIT_3 /* RFD Flexible Mode */ - -/*- RFD misc bits*/ -#define RFD_EOF_BIT BIT_15 /* RFD End-Of-Frame Bit */ -#define RFD_F_BIT BIT_14 /* RFD Buffer Fetch Bit */ -#define RFD_ACT_COUNT_MASK BIT_0_13 /* RFD Actual Count Mask */ - -/* Receive Buffer Descriptor Fields*/ -#define RBD_EOF_BIT BIT_15 /* RBD End-Of-Frame Bit */ -#define RBD_F_BIT BIT_14 /* RBD Buffer Fetch Bit */ -#define RBD_ACT_COUNT_MASK BIT_0_13 /* RBD Actual Count Mask */ - -#define SIZE_FIELD_MASK BIT_0_13 /* Size of the associated buffer */ -#define RBD_EL_BIT BIT_15 /* RBD EL Bit */ - -/* Self Test Results*/ -#define CB_SELFTEST_FAIL_BIT BIT_12 -#define CB_SELFTEST_DIAG_BIT BIT_5 -#define CB_SELFTEST_REGISTER_BIT BIT_3 -#define CB_SELFTEST_ROM_BIT BIT_2 - -#define CB_SELFTEST_ERROR_MASK ( \ - CB_SELFTEST_FAIL_BIT | CB_SELFTEST_DIAG_BIT | \ - CB_SELFTEST_REGISTER_BIT | CB_SELFTEST_ROM_BIT) - -/* adapter vendor & device ids */ -#define PCI_OHIO_BOARD 0x10f0 /* subdevice ID, Ohio dual port nic */ - -/* Values for PCI_REV_ID_REGISTER values */ -#define D101A4_REV_ID 4 /* 82558 A4 stepping */ -#define D101B0_REV_ID 5 /* 82558 B0 stepping */ -#define D101MA_REV_ID 8 /* 82559 A0 stepping */ -#define D101S_REV_ID 9 /* 82559S A-step */ -#define D102_REV_ID 12 -#define D102C_REV_ID 13 /* 82550 step C */ -#define D102E_REV_ID 15 - -/* ############Start of 82555 specific defines################## */ - -#define PHY_82555_LED_SWITCH_CONTROL 0x1b /* 82555 led switch control register */ - -/* 82555 led switch control reg. opcodes */ -#define PHY_82555_LED_NORMAL_CONTROL 0 // control back to the 8255X -#define PHY_82555_LED_DRIVER_CONTROL BIT_2 // the driver is in control -#define PHY_82555_LED_OFF BIT_2 // activity LED is off -#define PHY_82555_LED_ON_559 (BIT_0 | BIT_2) // activity LED is on for 559 and later -#define PHY_82555_LED_ON_PRE_559 (BIT_0 | BIT_1 | BIT_2) // activity LED is on for 558 and before - -// Describe the state of the phy led. -// needed for the function : 'e100_blink_timer' -enum led_state_e { - LED_OFF = 0, - LED_ON, -}; - -/* ############End of 82555 specific defines##################### */ - -#define RFD_PARSE_BIT BIT_3 -#define RFD_TCP_PACKET 0x00 -#define RFD_UDP_PACKET 0x01 -#define TCPUDP_CHECKSUM_BIT_VALID BIT_4 -#define TCPUDP_CHECKSUM_VALID BIT_5 -#define CHECKSUM_PROTOCOL_MASK 0x03 - -#define VLAN_SIZE 4 -#define CHKSUM_SIZE 2 -#define RFD_DATA_SIZE (ETH_FRAME_LEN + CHKSUM_SIZE + VLAN_SIZE) - -/* Bits for bdp->flags */ -#define DF_LINK_FC_CAP 0x00000001 /* Link is flow control capable */ -#define DF_CSUM_OFFLOAD 0x00000002 -#define DF_UCODE_LOADED 0x00000004 -#define USE_IPCB 0x00000008 /* set if using ipcb for transmits */ -#define IS_BACHELOR 0x00000010 /* set if 82558 or newer board */ -#define IS_ICH 0x00000020 -#define DF_SPEED_FORCED 0x00000040 /* set if speed is forced */ -#define LED_IS_ON 0x00000080 /* LED is turned ON by the driver */ -#define DF_LINK_FC_TX_ONLY 0x00000100 /* Received PAUSE frames are honored*/ - -typedef struct net_device_stats net_dev_stats_t; - -/* needed macros */ -/* These macros use the bdp pointer. If you use them it better be defined */ -#define PREV_TCB_USED(X) ((X).tail ? (X).tail - 1 : bdp->params.TxDescriptors - 1) -#define NEXT_TCB_TOUSE(X) ((((X) + 1) >= bdp->params.TxDescriptors) ? 0 : (X) + 1) -#define TCB_TO_USE(X) ((X).tail) -#define TCBS_AVAIL(X) (NEXT_TCB_TOUSE( NEXT_TCB_TOUSE((X).tail)) != (X).head) - -#define RFD_POINTER(skb,bdp) ((rfd_t *) (((unsigned char *)((skb)->data))-((bdp)->rfd_size))) -#define SKB_RFD_STATUS(skb,bdp) ((RFD_POINTER((skb),(bdp)))->rfd_header.cb_status) - -/* ====================================================================== */ -/* 82557 */ -/* ====================================================================== */ - -/* Changed for 82558 enhancement */ -typedef struct _d101_scb_ext_t { - u32 scb_rx_dma_cnt; /* Rx DMA byte count */ - u8 scb_early_rx_int; /* Early Rx DMA byte count */ - u8 scb_fc_thld; /* Flow Control threshold */ - u8 scb_fc_xon_xoff; /* Flow Control XON/XOFF values */ - u8 scb_pmdr; /* Power Mgmt. Driver Reg */ -} d101_scb_ext __attribute__ ((__packed__)); - -/* Changed for 82559 enhancement */ -typedef struct _d101m_scb_ext_t { - u32 scb_rx_dma_cnt; /* Rx DMA byte count */ - u8 scb_early_rx_int; /* Early Rx DMA byte count */ - u8 scb_fc_thld; /* Flow Control threshold */ - u8 scb_fc_xon_xoff; /* Flow Control XON/XOFF values */ - u8 scb_pmdr; /* Power Mgmt. Driver Reg */ - u8 scb_gen_ctrl; /* General Control */ - u8 scb_gen_stat; /* General Status */ - u16 scb_reserved; /* Reserved */ - u32 scb_function_event; /* Cardbus Function Event */ - u32 scb_function_event_mask; /* Cardbus Function Mask */ - u32 scb_function_present_state; /* Cardbus Function state */ - u32 scb_force_event; /* Cardbus Force Event */ -} d101m_scb_ext __attribute__ ((__packed__)); - -/* Changed for 82550 enhancement */ -typedef struct _d102_scb_ext_t { - u32 scb_rx_dma_cnt; /* Rx DMA byte count */ - u8 scb_early_rx_int; /* Early Rx DMA byte count */ - u8 scb_fc_thld; /* Flow Control threshold */ - u8 scb_fc_xon_xoff; /* Flow Control XON/XOFF values */ - u8 scb_pmdr; /* Power Mgmt. Driver Reg */ - u8 scb_gen_ctrl; /* General Control */ - u8 scb_gen_stat; /* General Status */ - u8 scb_gen_ctrl2; - u8 scb_reserved; /* Reserved */ - u32 scb_scheduling_reg; - u32 scb_reserved2; - u32 scb_function_event; /* Cardbus Function Event */ - u32 scb_function_event_mask; /* Cardbus Function Mask */ - u32 scb_function_present_state; /* Cardbus Function state */ - u32 scb_force_event; /* Cardbus Force Event */ -} d102_scb_ext __attribute__ ((__packed__)); - -/* - * 82557 status control block. this will be memory mapped & will hang of the - * the bdp, which hangs of the bdp. This is the brain of it. - */ -typedef struct _scb_t { - u16 scb_status; /* SCB Status register */ - u8 scb_cmd_low; /* SCB Command register (low byte) */ - u8 scb_cmd_hi; /* SCB Command register (high byte) */ - u32 scb_gen_ptr; /* SCB General pointer */ - u32 scb_port; /* PORT register */ - u16 scb_flsh_cntrl; /* Flash Control register */ - u16 scb_eprm_cntrl; /* EEPROM control register */ - u32 scb_mdi_cntrl; /* MDI Control Register */ - /* Changed for 82558 enhancement */ - union { - u32 scb_rx_dma_cnt; /* Rx DMA byte count */ - d101_scb_ext d101_scb; /* 82558/9 specific fields */ - d101m_scb_ext d101m_scb; /* 82559 specific fields */ - d102_scb_ext d102_scb; - } scb_ext; -} scb_t __attribute__ ((__packed__)); - -/* Self test - * This is used to dump results of the self test - */ -typedef struct _self_test_t { - u32 st_sign; /* Self Test Signature */ - u32 st_result; /* Self Test Results */ -} self_test_t __attribute__ ((__packed__)); - -/* - * Statistical Counters - */ -/* 82557 counters */ -typedef struct _basic_cntr_t { - u32 xmt_gd_frames; /* Good frames transmitted */ - u32 xmt_max_coll; /* Fatal frames -- had max collisions */ - u32 xmt_late_coll; /* Fatal frames -- had a late coll. */ - u32 xmt_uruns; /* Xmit underruns (fatal or re-transmit) */ - u32 xmt_lost_crs; /* Frames transmitted without CRS */ - u32 xmt_deferred; /* Deferred transmits */ - u32 xmt_sngl_coll; /* Transmits that had 1 and only 1 coll. */ - u32 xmt_mlt_coll; /* Transmits that had multiple coll. */ - u32 xmt_ttl_coll; /* Transmits that had 1+ collisions. */ - u32 rcv_gd_frames; /* Good frames received */ - u32 rcv_crc_errs; /* Aligned frames that had a CRC error */ - u32 rcv_algn_errs; /* Receives that had alignment errors */ - u32 rcv_rsrc_err; /* Good frame dropped cuz no resources */ - u32 rcv_oruns; /* Overrun errors - bus was busy */ - u32 rcv_err_coll; /* Received frms. that encountered coll. */ - u32 rcv_shrt_frames; /* Received frames that were to short */ -} basic_cntr_t; - -/* 82558 extended statistic counters */ -typedef struct _ext_cntr_t { - u32 xmt_fc_frames; - u32 rcv_fc_frames; - u32 rcv_fc_unsupported; -} ext_cntr_t; - -/* 82559 TCO statistic counters */ -typedef struct _tco_cntr_t { - u16 xmt_tco_frames; - u16 rcv_tco_frames; -} tco_cntr_t; - -/* Structures to access thet physical dump area */ -/* Use one of these types, according to the statisitcal counters mode, - to cast the pointer to the physical dump area and access the cmd_complete - DWORD. */ - -/* 557-mode : only basic counters + cmd_complete */ -typedef struct _err_cntr_557_t { - basic_cntr_t basic_stats; - u32 cmd_complete; -} err_cntr_557_t; - -/* 558-mode : basic + extended counters + cmd_complete */ -typedef struct _err_cntr_558_t { - basic_cntr_t basic_stats; - ext_cntr_t extended_stats; - u32 cmd_complete; -} err_cntr_558_t; - -/* 559-mode : basic + extended + TCO counters + cmd_complete */ -typedef struct _err_cntr_559_t { - basic_cntr_t basic_stats; - ext_cntr_t extended_stats; - tco_cntr_t tco_stats; - u32 cmd_complete; -} err_cntr_559_t; - -/* This typedef defines the struct needed to hold the largest number of counters */ -typedef err_cntr_559_t max_counters_t; - -/* Different statistical-counters mode the controller may be in */ -typedef enum _stat_mode_t { - E100_BASIC_STATS = 0, /* 82557 stats : 16 counters / 16 dw */ - E100_EXTENDED_STATS, /* 82558 stats : 19 counters / 19 dw */ - E100_TCO_STATS /* 82559 stats : 21 counters / 20 dw */ -} stat_mode_t; - -/* dump statistical counters complete codes */ -#define DUMP_STAT_COMPLETED 0xA005 -#define DUMP_RST_STAT_COMPLETED 0xA007 - -/* Command Block (CB) Generic Header Structure*/ -typedef struct _cb_header_t { - u16 cb_status; /* Command Block Status */ - u16 cb_cmd; /* Command Block Command */ - u32 cb_lnk_ptr; /* Link To Next CB */ -} cb_header_t __attribute__ ((__packed__)); - -//* Individual Address Command Block (IA_CB)*/ -typedef struct _ia_cb_t { - cb_header_t ia_cb_hdr; - u8 ia_addr[ETH_ALEN]; -} ia_cb_t __attribute__ ((__packed__)); - -/* Configure Command Block (CONFIG_CB)*/ -typedef struct _config_cb_t { - cb_header_t cfg_cbhdr; - u8 cfg_byte[CB_CFIG_BYTE_COUNT + CB_CFIG_D102_BYTE_COUNT]; -} config_cb_t __attribute__ ((__packed__)); - -/* MultiCast Command Block (MULTICAST_CB)*/ -typedef struct _multicast_cb_t { - cb_header_t mc_cbhdr; - u16 mc_count; /* Number of multicast addresses */ - u8 mc_addr[(ETH_ALEN * MAX_MULTICAST_ADDRS)]; -} mltcst_cb_t __attribute__ ((__packed__)); - -#define UCODE_MAX_DWORDS 134 -/* Load Microcode Command Block (LOAD_UCODE_CB)*/ -typedef struct _load_ucode_cb_t { - cb_header_t load_ucode_cbhdr; - u32 ucode_dword[UCODE_MAX_DWORDS]; -} load_ucode_cb_t __attribute__ ((__packed__)); - -/* Load Programmable Filter Data*/ -typedef struct _filter_cb_t { - cb_header_t filter_cb_hdr; - u32 filter_data[MAX_FILTER]; -} filter_cb_t __attribute__ ((__packed__)); - -/* NON_TRANSMIT_CB -- Generic Non-Transmit Command Block - */ -typedef struct _nxmit_cb_t { - union { - config_cb_t config; - ia_cb_t setup; - load_ucode_cb_t load_ucode; - mltcst_cb_t multicast; - filter_cb_t filter; - } ntcb; -} nxmit_cb_t __attribute__ ((__packed__)); - -/*Block for queuing for postponed execution of the non-transmit commands*/ -typedef struct _nxmit_cb_entry_t { - struct list_head list_elem; - nxmit_cb_t *non_tx_cmd; - dma_addr_t dma_addr; - unsigned long expiration_time; -} nxmit_cb_entry_t; - -/* States for postponed non tx commands execution */ -typedef enum _non_tx_cmd_state_t { - E100_NON_TX_IDLE = 0, /* No queued NON-TX commands */ - E100_WAIT_TX_FINISH, /* Wait for completion of the TX activities */ - E100_WAIT_NON_TX_FINISH /* Wait for completion of the non TX command */ -} non_tx_cmd_state_t; - -/* some defines for the ipcb */ -#define IPCB_IP_CHECKSUM_ENABLE BIT_4 -#define IPCB_TCPUDP_CHECKSUM_ENABLE BIT_5 -#define IPCB_TCP_PACKET BIT_6 -#define IPCB_LARGESEND_ENABLE BIT_7 -#define IPCB_HARDWAREPARSING_ENABLE BIT_0 -#define IPCB_INSERTVLAN_ENABLE BIT_1 -#define IPCB_IP_ACTIVATION_DEFAULT IPCB_HARDWAREPARSING_ENABLE - -/* Transmit Buffer Descriptor (TBD)*/ -typedef struct _tbd_t { - u32 tbd_buf_addr; /* Physical Transmit Buffer Address */ - u16 tbd_buf_cnt; /* Actual Count Of Bytes */ - u16 padd; -} tbd_t __attribute__ ((__packed__)); - -/* d102 specific fields */ -typedef struct _tcb_ipcb_t { - u16 schedule_low; - u8 ip_schedule; - u8 ip_activation_high; - u16 vlan; - u8 ip_header_offset; - u8 tcp_header_offset; - union { - u32 sec_rec_phys_addr; - u32 tbd_zero_address; - } tbd_sec_addr; - union { - u16 sec_rec_size; - u16 tbd_zero_size; - } tbd_sec_size; - u16 total_tcp_payload; -} tcb_ipcb_t __attribute__ ((__packed__)); - -#define E100_TBD_ARRAY_SIZE (2+MAX_SKB_FRAGS) - -/* Transmit Command Block (TCB)*/ -struct _tcb_t { - cb_header_t tcb_hdr; - u32 tcb_tbd_ptr; /* TBD address */ - u16 tcb_cnt; /* Data Bytes In TCB past header */ - u8 tcb_thrshld; /* TX Threshold for FIFO Extender */ - u8 tcb_tbd_num; - - union { - tcb_ipcb_t ipcb; /* d102 ipcb fields */ - tbd_t tbd_array[E100_TBD_ARRAY_SIZE]; - } tcbu; - - /* From here onward we can dump anything we want as long as the - * size of the total structure is a multiple of a paragraph - * boundary ( i.e. -16 bit aligned ). - */ - tbd_t *tbd_ptr; - - u32 tcb_tbd_dflt_ptr; /* TBD address for non-segmented packet */ - u32 tcb_tbd_expand_ptr; /* TBD address for segmented packet */ - - struct sk_buff *tcb_skb; /* the associated socket buffer */ - dma_addr_t tcb_phys; /* phys addr of the TCB */ -} __attribute__ ((__packed__)); - -#define _TCB_T_ -typedef struct _tcb_t tcb_t; - -/* Receive Frame Descriptor (RFD) - will be using the simple model*/ -struct _rfd_t { - /* 8255x */ - cb_header_t rfd_header; - u32 rfd_rbd_ptr; /* Receive Buffer Descriptor Addr */ - u16 rfd_act_cnt; /* Number Of Bytes Received */ - u16 rfd_sz; /* Number Of Bytes In RFD */ - /* D102 aka Gamla */ - u16 vlanid; - u8 rcvparserstatus; - u8 reserved; - u16 securitystatus; - u8 checksumstatus; - u8 zerocopystatus; - u8 pad[8]; /* data should be 16 byte aligned */ - u8 data[RFD_DATA_SIZE]; - -} __attribute__ ((__packed__)); - -#define _RFD_T_ -typedef struct _rfd_t rfd_t; - -/* Receive Buffer Descriptor (RBD)*/ -typedef struct _rbd_t { - u16 rbd_act_cnt; /* Number Of Bytes Received */ - u16 rbd_filler; - u32 rbd_lnk_addr; /* Link To Next RBD */ - u32 rbd_rcb_addr; /* Receive Buffer Address */ - u16 rbd_sz; /* Receive Buffer Size */ - u16 rbd_filler1; -} rbd_t __attribute__ ((__packed__)); - -/* - * This structure is used to maintain a FIFO access to a resource that is - * maintained as a circular queue. The resource to be maintained is pointed - * to by the "data" field in the structure below. In this driver the TCBs', - * TBDs' & RFDs' are maintained as a circular queue & are managed thru this - * structure. - */ -typedef struct _buf_pool_t { - unsigned int head; /* index to first used resource */ - unsigned int tail; /* index to last used resource */ - void *data; /* points to resource pool */ -} buf_pool_t; - -/*Rx skb holding structure*/ -struct rx_list_elem { - struct list_head list_elem; - dma_addr_t dma_addr; - struct sk_buff *skb; -}; - -enum next_cu_cmd_e { RESUME_NO_WAIT = 0, RESUME_WAIT, START_WAIT }; -enum zlock_state_e { ZLOCK_INITIAL, ZLOCK_READING, ZLOCK_SLEEPING }; -enum tx_queue_stop_type { LONG_STOP = 0, SHORT_STOP }; - -/* 64 bit aligned size */ -#define E100_SIZE_64A(X) ((sizeof(X) + 7) & ~0x7) - -typedef struct _bd_dma_able_t { - char selftest[E100_SIZE_64A(self_test_t)]; - char stats_counters[E100_SIZE_64A(max_counters_t)]; -} bd_dma_able_t; - -/* bit masks for bool parameters */ -#define PRM_XSUMRX 0x00000001 -#define PRM_UCODE 0x00000002 -#define PRM_FC 0x00000004 -#define PRM_IFS 0x00000008 -#define PRM_BUNDLE_SMALL 0x00000010 - -struct cfg_params { - int e100_speed_duplex; - int RxDescriptors; - int TxDescriptors; - int IntDelay; - int BundleMax; - int ber; - u32 b_params; -}; -struct ethtool_lpbk_data{ - dma_addr_t dma_handle; - tcb_t *tcb; - rfd_t *rfd; - -}; - -struct e100_private { - struct vlan_group *vlgrp; - u32 flags; /* board management flags */ - u32 tx_per_underrun; /* number of good tx frames per underrun */ - unsigned int tx_count; /* count of tx frames, so we can request an interrupt */ - u8 tx_thld; /* stores transmit threshold */ - u16 eeprom_size; - u32 pwa_no; /* PWA: xxxxxx-0xx */ - u8 perm_node_address[ETH_ALEN]; - struct list_head active_rx_list; /* list of rx buffers */ - struct list_head rx_struct_pool; /* pool of rx buffer struct headers */ - u16 rfd_size; /* size of the adapter's RFD struct */ - int skb_req; /* number of skbs neede by the adapter */ - u8 intr_mask; /* mask for interrupt status */ - - void *dma_able; /* dma allocated structs */ - dma_addr_t dma_able_phys; - self_test_t *selftest; /* pointer to self test area */ - dma_addr_t selftest_phys; /* phys addr of selftest */ - max_counters_t *stats_counters; /* pointer to stats table */ - dma_addr_t stat_cnt_phys; /* phys addr of stat counter area */ - - stat_mode_t stat_mode; /* statistics mode: extended, TCO, basic */ - scb_t *scb; /* memory mapped ptr to 82557 scb */ - - tcb_t *last_tcb; /* pointer to last tcb sent */ - buf_pool_t tcb_pool; /* adapter's TCB array */ - dma_addr_t tcb_phys; /* phys addr of start of TCBs */ - - u16 cur_line_speed; - u16 cur_dplx_mode; - - struct net_device *device; - struct pci_dev *pdev; - struct driver_stats drv_stats; - - u8 rev_id; /* adapter PCI revision ID */ - - unsigned int phy_addr; /* address of PHY component */ - unsigned int PhyId; /* ID of PHY component */ - unsigned int PhyState; /* state for the fix squelch algorithm */ - unsigned int PhyDelay; /* delay for the fix squelch algorithm */ - - /* Lock defintions for the driver */ - spinlock_t bd_lock; /* board lock */ - spinlock_t bd_non_tx_lock; /* Non transmit command lock */ - spinlock_t config_lock; /* config block lock */ - spinlock_t mdi_access_lock; /* mdi lock */ - - struct timer_list watchdog_timer; /* watchdog timer id */ - - /* non-tx commands parameters */ - struct timer_list nontx_timer_id; /* non-tx timer id */ - struct list_head non_tx_cmd_list; - non_tx_cmd_state_t non_tx_command_state; - nxmit_cb_entry_t *same_cmd_entry[CB_MAX_NONTX_CMD]; - - enum next_cu_cmd_e next_cu_cmd; - - /* Zero Locking Algorithm data members */ - enum zlock_state_e zlock_state; - u8 zlock_read_data[16]; /* number of times each value 0-15 was read */ - u16 zlock_read_cnt; /* counts number of reads */ - ulong zlock_sleep_cnt; /* keeps track of "sleep" time */ - - u8 config[CB_CFIG_BYTE_COUNT + CB_CFIG_D102_BYTE_COUNT]; - - /* IFS params */ - u8 ifs_state; - u8 ifs_value; - - struct cfg_params params; /* adapter's command line parameters */ - - u32 speed_duplex_caps; /* adapter's speed/duplex capabilities */ - - /* WOL params for ethtool */ - u32 wolsupported; - u32 wolopts; - u16 ip_lbytes; - struct ethtool_lpbk_data loopback; - struct timer_list blink_timer; /* led blink timer id */ - -#ifdef CONFIG_PM - u32 pci_state[16]; -#endif -#ifdef E100_CU_DEBUG - u8 last_cmd; - u8 last_sub_cmd; -#endif -}; - -#define E100_AUTONEG 0 -#define E100_SPEED_10_HALF 1 -#define E100_SPEED_10_FULL 2 -#define E100_SPEED_100_HALF 3 -#define E100_SPEED_100_FULL 4 - -/********* function prototypes *************/ -extern int e100_open(struct net_device *); -extern int e100_close(struct net_device *); -extern void e100_isolate_driver(struct e100_private *bdp); -extern unsigned char e100_hw_init(struct e100_private *); -extern void e100_sw_reset(struct e100_private *bdp, u32 reset_cmd); -extern u8 e100_start_cu(struct e100_private *bdp, tcb_t *tcb); -extern void e100_free_non_tx_cmd(struct e100_private *bdp, - nxmit_cb_entry_t *non_tx_cmd); -extern nxmit_cb_entry_t *e100_alloc_non_tx_cmd(struct e100_private *bdp); -extern unsigned char e100_exec_non_cu_cmd(struct e100_private *bdp, - nxmit_cb_entry_t *cmd); -extern unsigned char e100_selftest(struct e100_private *bdp, u32 *st_timeout, - u32 *st_result); -extern unsigned char e100_get_link_state(struct e100_private *bdp); -extern unsigned char e100_wait_scb(struct e100_private *bdp); - -extern void e100_deisolate_driver(struct e100_private *bdp, u8 full_reset); -extern unsigned char e100_configure_device(struct e100_private *bdp); -#ifdef E100_CU_DEBUG -extern unsigned char e100_cu_unknown_state(struct e100_private *bdp); -#endif - -#define ROM_TEST_FAIL 0x01 -#define REGISTER_TEST_FAIL 0x02 -#define SELF_TEST_FAIL 0x04 -#define TEST_TIMEOUT 0x08 - -enum test_offsets { - test_link, - test_eeprom, - test_self_test, - test_loopback_mac, - test_loopback_phy, - cable_diag, - max_test_res, /* must be last */ -}; - -#endif diff -Nru a/drivers/net/e100/e100_config.c b/drivers/net/e100/e100_config.c --- a/drivers/net/e100/e100_config.c Thu Jan 22 18:59:24 2004 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,639 +0,0 @@ -/******************************************************************************* - - - Copyright(c) 1999 - 2003 Intel Corporation. All rights reserved. - - This program is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by the Free - Software Foundation; either version 2 of the License, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - this program; if not, write to the Free Software Foundation, Inc., 59 - Temple Place - Suite 330, Boston, MA 02111-1307, USA. - - The full GNU General Public License is included in this distribution in the - file called LICENSE. - - Contact Information: - Linux NICS - Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 -*******************************************************************************/ - -/********************************************************************** -* * -* INTEL CORPORATION * -* * -* This software is supplied under the terms of the license included * -* above. All use of this driver must be in accordance with the terms * -* of that license. * -* * -* Module Name: e100_config.c * -* * -* Abstract: Functions for configuring the network adapter. * -* * -* Environment: This file is intended to be specific to the Linux * -* operating system. * -* * -**********************************************************************/ -#include "e100_config.h" - -static void e100_config_long_rx(struct e100_private *bdp, unsigned char enable); - -static const u8 def_config[] = { - CB_CFIG_BYTE_COUNT, - 0x08, 0x00, 0x00, 0x00, 0x00, 0x32, 0x07, 0x01, - 0x00, 0x2e, 0x00, 0x60, 0x00, 0xf2, 0xc8, 0x00, - 0x40, 0xf2, 0x80, 0x3f, 0x05 -}; - -/** - * e100_config_init_82557 - config the 82557 adapter - * @bdp: atapter's private data struct - * - * This routine will initialize the 82557 configure block. - * All other init functions will only set values that are - * different from the 82557 default. - */ -void -e100_config_init_82557(struct e100_private *bdp) -{ - /* initialize config block */ - memcpy(bdp->config, def_config, sizeof (def_config)); - bdp->config[0] = CB_CFIG_BYTE_COUNT; /* just in case */ - - e100_config_ifs(bdp); - - /* - * Enable extended statistical counters (82558 and up) and TCO counters - * (82559 and up) and set the statistical counters' mode in bdp - * - * stat. mode | TCO stat. bit (2) | Extended stat. bit (5) - * ------------------------------------------------------------------ - * Basic (557) | 0 | 1 - * ------------------------------------------------------------------ - * Extended (558) | 0 | 0 - * ------------------------------------------------------------------ - * TCO (559) | 1 | 1 - * ------------------------------------------------------------------ - * Reserved | 1 | 0 - * ------------------------------------------------------------------ - */ - bdp->config[6] &= ~CB_CFIG_TCO_STAT; - bdp->config[6] |= CB_CFIG_EXT_STAT_DIS; - bdp->stat_mode = E100_BASIC_STATS; - - /* Setup for MII or 503 operation. The CRS+CDT bit should only be set */ - /* when operating in 503 mode. */ - if (bdp->phy_addr == 32) { - bdp->config[8] &= ~CB_CFIG_503_MII; - bdp->config[15] |= CB_CFIG_CRS_OR_CDT; - } else { - bdp->config[8] |= CB_CFIG_503_MII; - bdp->config[15] &= ~CB_CFIG_CRS_OR_CDT; - } - - e100_config_fc(bdp); - e100_config_force_dplx(bdp); - e100_config_promisc(bdp, false); - e100_config_mulcast_enbl(bdp, false); -} - -static void -e100_config_init_82558(struct e100_private *bdp) -{ - /* MWI enable. This should be turned on only if the adapter is a 82558/9 - * and if the PCI command reg. has enabled the MWI bit. */ - bdp->config[3] |= CB_CFIG_MWI_EN; - - bdp->config[6] &= ~CB_CFIG_EXT_TCB_DIS; - - if (bdp->rev_id >= D101MA_REV_ID) { - /* this is 82559 and up - enable TCO counters */ - bdp->config[6] |= CB_CFIG_TCO_STAT; - bdp->config[6] |= CB_CFIG_EXT_STAT_DIS; - bdp->stat_mode = E100_TCO_STATS; - - if ((bdp->rev_id < D102_REV_ID) && - (bdp->params.b_params & PRM_XSUMRX) && - (bdp->pdev->device != 0x1209)) { - - bdp->flags |= DF_CSUM_OFFLOAD; - bdp->config[9] |= 1; - } - } else { - /* this is 82558 */ - bdp->config[6] &= ~CB_CFIG_TCO_STAT; - bdp->config[6] &= ~CB_CFIG_EXT_STAT_DIS; - bdp->stat_mode = E100_EXTENDED_STATS; - } - - e100_config_long_rx(bdp, true); -} - -static void -e100_config_init_82550(struct e100_private *bdp) -{ - /* The D102 chip allows for 32 config bytes. This value is - * supposed to be in Byte 0. Just add the extra bytes to - * what was already setup in the block. */ - bdp->config[0] += CB_CFIG_D102_BYTE_COUNT; - - /* now we need to enable the extended RFD. When this is - * enabled, the immediated receive data buffer starts at offset - * 32 from the RFD base address, instead of at offset 16. */ - bdp->config[7] |= CB_CFIG_EXTENDED_RFD; - - /* put the chip into D102 receive mode. This is necessary - * for any parsing and offloading features. */ - bdp->config[22] = CB_CFIG_RECEIVE_GAMLA_MODE; - - /* set the flag if checksum offloading was enabled */ - if (bdp->params.b_params & PRM_XSUMRX) { - bdp->flags |= DF_CSUM_OFFLOAD; - } -} - -/* Initialize the adapter's configure block */ -void -e100_config_init(struct e100_private *bdp) -{ - e100_config_init_82557(bdp); - - if (bdp->flags & IS_BACHELOR) - e100_config_init_82558(bdp); - - if (bdp->rev_id >= D102_REV_ID) - e100_config_init_82550(bdp); -} - -/** - * e100_force_config - force a configure command - * @bdp: atapter's private data struct - * - * This routine will force a configure command to the adapter. - * The command will be executed in polled mode as interrupts - * are _disabled_ at this time. - * - * Returns: - * true: if the configure command was successfully issued and completed - * false: otherwise - */ -unsigned char -e100_force_config(struct e100_private *bdp) -{ - spin_lock_bh(&(bdp->config_lock)); - - bdp->config[0] = CB_CFIG_BYTE_COUNT; - if (bdp->rev_id >= D102_REV_ID) { - /* The D102 chip allows for 32 config bytes. This value is - supposed to be in Byte 0. Just add the extra bytes to - what was already setup in the block. */ - bdp->config[0] += CB_CFIG_D102_BYTE_COUNT; - } - - spin_unlock_bh(&(bdp->config_lock)); - - // although we call config outside the lock, there is no - // race condition because config byte count has maximum value - return e100_config(bdp); -} - -/** - * e100_config - issue a configure command - * @bdp: atapter's private data struct - * - * This routine will issue a configure command to the 82557. - * This command will be executed in polled mode as interrupts - * are _disabled_ at this time. - * - * Returns: - * true: if the configure command was successfully issued and completed - * false: otherwise - */ -unsigned char -e100_config(struct e100_private *bdp) -{ - cb_header_t *pntcb_hdr; - unsigned char res = true; - nxmit_cb_entry_t *cmd; - - if (bdp->config[0] == 0) { - goto exit; - } - - if ((cmd = e100_alloc_non_tx_cmd(bdp)) == NULL) { - res = false; - goto exit; - } - - pntcb_hdr = (cb_header_t *) cmd->non_tx_cmd; - pntcb_hdr->cb_cmd = __constant_cpu_to_le16(CB_CONFIGURE); - - spin_lock_bh(&bdp->config_lock); - - if (bdp->config[0] < CB_CFIG_MIN_PARAMS) { - bdp->config[0] = CB_CFIG_MIN_PARAMS; - } - - /* Copy the device's config block to the device's memory */ - memcpy(cmd->non_tx_cmd->ntcb.config.cfg_byte, bdp->config, - bdp->config[0]); - /* reset number of bytes to config next time */ - bdp->config[0] = 0; - - spin_unlock_bh(&bdp->config_lock); - - res = e100_exec_non_cu_cmd(bdp, cmd); - -exit: - if (netif_running(bdp->device)) - netif_wake_queue(bdp->device); - return res; -} - -/** - * e100_config_fc - config flow-control state - * @bdp: adapter's private data struct - * - * This routine will enable or disable flow control support in the adapter's - * config block. Flow control will be enable only if requested using the command - * line option, and if the link is flow-contorl capable (both us and the link - * partner). But, if link partner is capable of autoneg, but not capable of - * flow control, received PAUSE frames are still honored. - */ -void -e100_config_fc(struct e100_private *bdp) -{ - unsigned char enable = false; - /* 82557 doesn't support fc. Don't touch this option */ - if (!(bdp->flags & IS_BACHELOR)) - return; - - /* Enable fc if requested and if the link supports it */ - if ((bdp->params.b_params & PRM_FC) && (bdp->flags & - (DF_LINK_FC_CAP | DF_LINK_FC_TX_ONLY))) { - enable = true; - } - - spin_lock_bh(&(bdp->config_lock)); - - if (enable) { - if (bdp->flags & DF_LINK_FC_TX_ONLY) { - /* If link partner is capable of autoneg, but */ - /* not capable of flow control, Received PAUSE */ - /* frames are still honored, i.e., */ - /* transmitted frames would be paused by */ - /* incoming PAUSE frames */ - bdp->config[16] = DFLT_NO_FC_DELAY_LSB; - bdp->config[17] = DFLT_NO_FC_DELAY_MSB; - bdp->config[19] &= ~(CB_CFIG_FC_RESTOP | CB_CFIG_FC_RESTART); - bdp->config[19] |= CB_CFIG_FC_REJECT; - bdp->config[19] &= ~CB_CFIG_TX_FC_DIS; - } else { - bdp->config[16] = DFLT_FC_DELAY_LSB; - bdp->config[17] = DFLT_FC_DELAY_MSB; - bdp->config[19] |= CB_CFIG_FC_OPTS; - bdp->config[19] &= ~CB_CFIG_TX_FC_DIS; - } - } else { - bdp->config[16] = DFLT_NO_FC_DELAY_LSB; - bdp->config[17] = DFLT_NO_FC_DELAY_MSB; - bdp->config[19] &= ~CB_CFIG_FC_OPTS; - bdp->config[19] |= CB_CFIG_TX_FC_DIS; - } - E100_CONFIG(bdp, 19); - spin_unlock_bh(&(bdp->config_lock)); - - return; -} - -/** - * e100_config_promisc - configure promiscuous mode - * @bdp: atapter's private data struct - * @enable: should we enable this option or not - * - * This routine will enable or disable promiscuous mode - * in the adapter's config block. - */ -void -e100_config_promisc(struct e100_private *bdp, unsigned char enable) -{ - spin_lock_bh(&(bdp->config_lock)); - - /* if in promiscuous mode, save bad frames */ - if (enable) { - - if (!(bdp->config[6] & CB_CFIG_SAVE_BAD_FRAMES)) { - bdp->config[6] |= CB_CFIG_SAVE_BAD_FRAMES; - E100_CONFIG(bdp, 6); - } - - if (bdp->config[7] & (u8) BIT_0) { - bdp->config[7] &= (u8) (~BIT_0); - E100_CONFIG(bdp, 7); - } - - if (!(bdp->config[15] & CB_CFIG_PROMISCUOUS)) { - bdp->config[15] |= CB_CFIG_PROMISCUOUS; - E100_CONFIG(bdp, 15); - } - - } else { /* not in promiscuous mode */ - - if (bdp->config[6] & CB_CFIG_SAVE_BAD_FRAMES) { - bdp->config[6] &= ~CB_CFIG_SAVE_BAD_FRAMES; - E100_CONFIG(bdp, 6); - } - - if (!(bdp->config[7] & (u8) BIT_0)) { - bdp->config[7] |= (u8) (BIT_0); - E100_CONFIG(bdp, 7); - } - - if (bdp->config[15] & CB_CFIG_PROMISCUOUS) { - bdp->config[15] &= ~CB_CFIG_PROMISCUOUS; - E100_CONFIG(bdp, 15); - } - } - - spin_unlock_bh(&(bdp->config_lock)); -} - -/** - * e100_config_mulcast_enbl - configure allmulti mode - * @bdp: atapter's private data struct - * @enable: should we enable this option or not - * - * This routine will enable or disable reception of all multicast packets - * in the adapter's config block. - */ -void -e100_config_mulcast_enbl(struct e100_private *bdp, unsigned char enable) -{ - spin_lock_bh(&(bdp->config_lock)); - - /* this flag is used to enable receiving all multicast packet */ - if (enable) { - if (!(bdp->config[21] & CB_CFIG_MULTICAST_ALL)) { - bdp->config[21] |= CB_CFIG_MULTICAST_ALL; - E100_CONFIG(bdp, 21); - } - - } else { - if (bdp->config[21] & CB_CFIG_MULTICAST_ALL) { - bdp->config[21] &= ~CB_CFIG_MULTICAST_ALL; - E100_CONFIG(bdp, 21); - } - } - - spin_unlock_bh(&(bdp->config_lock)); -} - -/** - * e100_config_ifs - configure the IFS parameter - * @bdp: atapter's private data struct - * - * This routine will configure the adaptive IFS value - * in the adapter's config block. IFS values are only - * relevant in half duplex, so set to 0 in full duplex. - */ -void -e100_config_ifs(struct e100_private *bdp) -{ - u8 value = 0; - - spin_lock_bh(&(bdp->config_lock)); - - /* IFS value is only needed to be specified at half-duplex mode */ - if (bdp->cur_dplx_mode == HALF_DUPLEX) { - value = (u8) bdp->ifs_value; - } - - if (bdp->config[2] != value) { - bdp->config[2] = value; - E100_CONFIG(bdp, 2); - } - - spin_unlock_bh(&(bdp->config_lock)); -} - -/** - * e100_config_force_dplx - configure the forced full duplex mode - * @bdp: atapter's private data struct - * - * This routine will enable or disable force full duplex - * in the adapter's config block. If the PHY is 503, and - * the duplex is full, consider the adapter forced. - */ -void -e100_config_force_dplx(struct e100_private *bdp) -{ - spin_lock_bh(&(bdp->config_lock)); - - /* We must force full duplex on if we are using PHY 0, and we are */ - /* supposed to run in FDX mode. We do this because the e100 has only */ - /* one FDX# input pin, and that pin will be connected to PHY 1. */ - /* Changed the 'if' condition below to fix performance problem * at 10 - * full. The Phy was getting forced to full duplex while the MAC * was - * not, because the cur_dplx_mode was not being set to 2 by SetupPhy. * - * This is how the condition was, initially. * This has been changed so - * that the MAC gets forced to full duplex * simply if the user has - * forced full duplex. * * if (( bdp->phy_addr == 0 ) && ( - * bdp->cur_dplx_mode == 2 )) */ - /* The rest of the fix is in the PhyDetect code. */ - if ((bdp->params.e100_speed_duplex == E100_SPEED_10_FULL) || - (bdp->params.e100_speed_duplex == E100_SPEED_100_FULL) || - ((bdp->phy_addr == 32) && (bdp->cur_dplx_mode == FULL_DUPLEX))) { - if (!(bdp->config[19] & (u8) CB_CFIG_FORCE_FDX)) { - bdp->config[19] |= (u8) CB_CFIG_FORCE_FDX; - E100_CONFIG(bdp, 19); - } - - } else { - if (bdp->config[19] & (u8) CB_CFIG_FORCE_FDX) { - bdp->config[19] &= (u8) (~CB_CFIG_FORCE_FDX); - E100_CONFIG(bdp, 19); - } - } - - spin_unlock_bh(&(bdp->config_lock)); -} - -/** - * e100_config_long_rx - * @bdp: atapter's private data struct - * @enable: should we enable this option or not - * - * This routine will enable or disable reception of larger packets. - * This is needed by VLAN implementations. - */ -static void -e100_config_long_rx(struct e100_private *bdp, unsigned char enable) -{ - if (enable) { - if (!(bdp->config[18] & CB_CFIG_LONG_RX_OK)) { - bdp->config[18] |= CB_CFIG_LONG_RX_OK; - E100_CONFIG(bdp, 18); - } - - } else { - if ((bdp->config[18] & CB_CFIG_LONG_RX_OK)) { - bdp->config[18] &= ~CB_CFIG_LONG_RX_OK; - E100_CONFIG(bdp, 18); - } - } -} - -/** - * e100_config_wol - * @bdp: atapter's private data struct - * - * This sets configuration options for PHY and Magic Packet WoL - */ -void -e100_config_wol(struct e100_private *bdp) -{ - spin_lock_bh(&(bdp->config_lock)); - - if (bdp->wolopts & WAKE_PHY) { - bdp->config[9] |= CB_LINK_STATUS_WOL; - } - else { - /* Disable PHY WoL */ - bdp->config[9] &= ~CB_LINK_STATUS_WOL; - } - - if (bdp->wolopts & WAKE_MAGIC) { - bdp->config[19] &= ~CB_DISABLE_MAGPAK_WAKE; - } - else { - /* Disable Magic Packet WoL */ - bdp->config[19] |= CB_DISABLE_MAGPAK_WAKE; - } - - E100_CONFIG(bdp, 19); - spin_unlock_bh(&(bdp->config_lock)); -} - -void -e100_config_vlan_drop(struct e100_private *bdp, unsigned char enable) -{ - spin_lock_bh(&(bdp->config_lock)); - if (enable) { - if (!(bdp->config[22] & CB_CFIG_VLAN_DROP_ENABLE)) { - bdp->config[22] |= CB_CFIG_VLAN_DROP_ENABLE; - E100_CONFIG(bdp, 22); - } - - } else { - if ((bdp->config[22] & CB_CFIG_VLAN_DROP_ENABLE)) { - bdp->config[22] &= ~CB_CFIG_VLAN_DROP_ENABLE; - E100_CONFIG(bdp, 22); - } - } - spin_unlock_bh(&(bdp->config_lock)); -} - -/** - * e100_config_loopback_mode - * @bdp: atapter's private data struct - * @mode: loopback mode(phy/mac/none) - * - */ -unsigned char -e100_config_loopback_mode(struct e100_private *bdp, u8 mode) -{ - unsigned char bc_changed = false; - u8 config_byte; - - spin_lock_bh(&(bdp->config_lock)); - - switch (mode) { - case NO_LOOPBACK: - config_byte = CB_CFIG_LOOPBACK_NORMAL; - break; - case MAC_LOOPBACK: - config_byte = CB_CFIG_LOOPBACK_INTERNAL; - break; - case PHY_LOOPBACK: - config_byte = CB_CFIG_LOOPBACK_EXTERNAL; - break; - default: - printk(KERN_NOTICE "e100: e100_config_loopback_mode: " - "Invalid argument 'mode': %d\n", mode); - goto exit; - } - - if ((bdp->config[10] & CB_CFIG_LOOPBACK_MODE) != config_byte) { - - bdp->config[10] &= (~CB_CFIG_LOOPBACK_MODE); - bdp->config[10] |= config_byte; - E100_CONFIG(bdp, 10); - bc_changed = true; - } - -exit: - spin_unlock_bh(&(bdp->config_lock)); - return bc_changed; -} -unsigned char -e100_config_tcb_ext_enable(struct e100_private *bdp, unsigned char enable) -{ - unsigned char bc_changed = false; - - spin_lock_bh(&(bdp->config_lock)); - - if (enable) { - if (bdp->config[6] & CB_CFIG_EXT_TCB_DIS) { - - bdp->config[6] &= (~CB_CFIG_EXT_TCB_DIS); - E100_CONFIG(bdp, 6); - bc_changed = true; - } - - } else { - if (!(bdp->config[6] & CB_CFIG_EXT_TCB_DIS)) { - - bdp->config[6] |= CB_CFIG_EXT_TCB_DIS; - E100_CONFIG(bdp, 6); - bc_changed = true; - } - } - spin_unlock_bh(&(bdp->config_lock)); - - return bc_changed; -} -unsigned char -e100_config_dynamic_tbd(struct e100_private *bdp, unsigned char enable) -{ - unsigned char bc_changed = false; - - spin_lock_bh(&(bdp->config_lock)); - - if (enable) { - if (!(bdp->config[7] & CB_CFIG_DYNTBD_EN)) { - - bdp->config[7] |= CB_CFIG_DYNTBD_EN; - E100_CONFIG(bdp, 7); - bc_changed = true; - } - - } else { - if (bdp->config[7] & CB_CFIG_DYNTBD_EN) { - - bdp->config[7] &= (~CB_CFIG_DYNTBD_EN); - E100_CONFIG(bdp, 7); - bc_changed = true; - } - } - spin_unlock_bh(&(bdp->config_lock)); - - return bc_changed; -} - diff -Nru a/drivers/net/e100/e100_config.h b/drivers/net/e100/e100_config.h --- a/drivers/net/e100/e100_config.h Thu Jan 22 18:59:24 2004 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,168 +0,0 @@ -/******************************************************************************* - - - Copyright(c) 1999 - 2003 Intel Corporation. All rights reserved. - - This program is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by the Free - Software Foundation; either version 2 of the License, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - this program; if not, write to the Free Software Foundation, Inc., 59 - Temple Place - Suite 330, Boston, MA 02111-1307, USA. - - The full GNU General Public License is included in this distribution in the - file called LICENSE. - - Contact Information: - Linux NICS - Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 -*******************************************************************************/ - -#ifndef _E100_CONFIG_INC_ -#define _E100_CONFIG_INC_ - -#include "e100.h" - -#define E100_CONFIG(bdp, X) ((bdp)->config[0] = max_t(u8, (bdp)->config[0], (X)+1)) - -#define CB_CFIG_MIN_PARAMS 8 - -/* byte 0 bit definitions*/ -#define CB_CFIG_BYTE_COUNT_MASK BIT_0_5 /* Byte count occupies bit 5-0 */ - -/* byte 1 bit definitions*/ -#define CB_CFIG_RXFIFO_LIMIT_MASK BIT_0_4 /* RxFifo limit mask */ -#define CB_CFIG_TXFIFO_LIMIT_MASK BIT_4_7 /* TxFifo limit mask */ - -/* byte 2 bit definitions -- ADAPTIVE_IFS*/ - -/* word 3 bit definitions -- RESERVED*/ -/* Changed for 82558 enhancements */ -/* byte 3 bit definitions */ -#define CB_CFIG_MWI_EN BIT_0 /* Enable MWI on PCI bus */ -#define CB_CFIG_TYPE_EN BIT_1 /* Type Enable */ -#define CB_CFIG_READAL_EN BIT_2 /* Enable Read Align */ -#define CB_CFIG_TERMCL_EN BIT_3 /* Cache line write */ - -/* byte 4 bit definitions*/ -#define CB_CFIG_RX_MIN_DMA_MASK BIT_0_6 /* Rx minimum DMA count mask */ - -/* byte 5 bit definitions*/ -#define CB_CFIG_TX_MIN_DMA_MASK BIT_0_6 /* Tx minimum DMA count mask */ -#define CB_CFIG_DMBC_EN BIT_7 /* Enable Tx/Rx min. DMA counts */ - -/* Changed for 82558 enhancements */ -/* byte 6 bit definitions*/ -#define CB_CFIG_LATE_SCB BIT_0 /* Update SCB After New Tx Start */ -#define CB_CFIG_DIRECT_DMA_DIS BIT_1 /* Direct DMA mode */ -#define CB_CFIG_TNO_INT BIT_2 /* Tx Not OK Interrupt */ -#define CB_CFIG_TCO_STAT BIT_2 /* TCO statistics in 559 and above */ -#define CB_CFIG_CI_INT BIT_3 /* Command Complete Interrupt */ -#define CB_CFIG_EXT_TCB_DIS BIT_4 /* Extended TCB */ -#define CB_CFIG_EXT_STAT_DIS BIT_5 /* Extended Stats */ -#define CB_CFIG_SAVE_BAD_FRAMES BIT_7 /* Save Bad Frames Enabled */ - -/* byte 7 bit definitions*/ -#define CB_CFIG_DISC_SHORT_FRAMES BIT_0 /* Discard Short Frames */ -#define CB_CFIG_DYNTBD_EN BIT_7 /* Enable dynamic TBD */ -/* Enable extended RFD's on D102 */ -#define CB_CFIG_EXTENDED_RFD BIT_5 - -/* byte 8 bit definitions*/ -#define CB_CFIG_503_MII BIT_0 /* 503 vs. MII mode */ - -/* byte 9 bit definitions -- pre-defined all zeros*/ -#define CB_LINK_STATUS_WOL BIT_5 - -/* byte 10 bit definitions*/ -#define CB_CFIG_NO_SRCADR BIT_3 /* No Source Address Insertion */ -#define CB_CFIG_PREAMBLE_LEN BIT_4_5 /* Preamble Length */ -#define CB_CFIG_LOOPBACK_MODE BIT_6_7 /* Loopback Mode */ -#define CB_CFIG_LOOPBACK_NORMAL 0 -#define CB_CFIG_LOOPBACK_INTERNAL BIT_6 -#define CB_CFIG_LOOPBACK_EXTERNAL BIT_6_7 - -/* byte 11 bit definitions*/ -#define CB_CFIG_LINEAR_PRIORITY BIT_0_2 /* Linear Priority */ - -/* byte 12 bit definitions*/ -#define CB_CFIG_LINEAR_PRI_MODE BIT_0 /* Linear Priority mode */ -#define CB_CFIG_IFS_MASK BIT_4_7 /* Interframe Spacing mask */ - -/* byte 13 bit definitions -- pre-defined all zeros*/ - -/* byte 14 bit definitions -- pre-defined 0xf2*/ - -/* byte 15 bit definitions*/ -#define CB_CFIG_PROMISCUOUS BIT_0 /* Promiscuous Mode Enable */ -#define CB_CFIG_BROADCAST_DIS BIT_1 /* Broadcast Mode Disable */ -#define CB_CFIG_CRS_OR_CDT BIT_7 /* CRS Or CDT */ - -/* byte 16 bit definitions -- pre-defined all zeros*/ -#define DFLT_FC_DELAY_LSB 0x1f /* Delay for outgoing Pause frames */ -#define DFLT_NO_FC_DELAY_LSB 0x00 /* no flow control default value */ - -/* byte 17 bit definitions -- pre-defined 0x40*/ -#define DFLT_FC_DELAY_MSB 0x01 /* Delay for outgoing Pause frames */ -#define DFLT_NO_FC_DELAY_MSB 0x40 /* no flow control default value */ - -/* byte 18 bit definitions*/ -#define CB_CFIG_STRIPPING BIT_0 /* Padding Disabled */ -#define CB_CFIG_PADDING BIT_1 /* Padding Disabled */ -#define CB_CFIG_CRC_IN_MEM BIT_2 /* Transfer CRC To Memory */ - -/* byte 19 bit definitions*/ -#define CB_CFIG_TX_ADDR_WAKE BIT_0 /* Address Wakeup */ -#define CB_DISABLE_MAGPAK_WAKE BIT_1 /* Magic Packet Wakeup disable */ -/* Changed TX_FC_EN to TX_FC_DIS because 0 enables, 1 disables. Jul 8, 1999 */ -#define CB_CFIG_TX_FC_DIS BIT_2 /* Tx Flow Control Disable */ -#define CB_CFIG_FC_RESTOP BIT_3 /* Rx Flow Control Restop */ -#define CB_CFIG_FC_RESTART BIT_4 /* Rx Flow Control Restart */ -#define CB_CFIG_FC_REJECT BIT_5 /* Rx Flow Control Restart */ -#define CB_CFIG_FC_OPTS (CB_CFIG_FC_RESTOP | CB_CFIG_FC_RESTART | CB_CFIG_FC_REJECT) - -/* end 82558/9 specifics */ - -#define CB_CFIG_FORCE_FDX BIT_6 /* Force Full Duplex */ -#define CB_CFIG_FDX_ENABLE BIT_7 /* Full Duplex Enabled */ - -/* byte 20 bit definitions*/ -#define CB_CFIG_MULTI_IA BIT_6 /* Multiple IA Addr */ - -/* byte 21 bit definitions*/ -#define CB_CFIG_MULTICAST_ALL BIT_3 /* Multicast All */ - -/* byte 22 bit defines */ -#define CB_CFIG_RECEIVE_GAMLA_MODE BIT_0 /* D102 receive mode */ -#define CB_CFIG_VLAN_DROP_ENABLE BIT_1 /* vlan stripping */ - -#define CB_CFIG_LONG_RX_OK BIT_3 - -#define NO_LOOPBACK 0 -#define MAC_LOOPBACK 0x01 -#define PHY_LOOPBACK 0x02 - -/* function prototypes */ -extern void e100_config_init(struct e100_private *bdp); -extern void e100_config_init_82557(struct e100_private *bdp); -extern unsigned char e100_force_config(struct e100_private *bdp); -extern unsigned char e100_config(struct e100_private *bdp); -extern void e100_config_fc(struct e100_private *bdp); -extern void e100_config_promisc(struct e100_private *bdp, unsigned char enable); -extern void e100_config_brdcast_dsbl(struct e100_private *bdp); -extern void e100_config_mulcast_enbl(struct e100_private *bdp, - unsigned char enable); -extern void e100_config_ifs(struct e100_private *bdp); -extern void e100_config_force_dplx(struct e100_private *bdp); -extern u8 e100_config_loopback_mode(struct e100_private *bdp, u8 mode); -extern u8 e100_config_dynamic_tbd(struct e100_private *bdp, u8 enable); -extern u8 e100_config_tcb_ext_enable(struct e100_private *bdp, u8 enable); -extern void e100_config_vlan_drop(struct e100_private *bdp, unsigned char enable); -#endif /* _E100_CONFIG_INC_ */ diff -Nru a/drivers/net/e100/e100_eeprom.c b/drivers/net/e100/e100_eeprom.c --- a/drivers/net/e100/e100_eeprom.c Thu Jan 22 18:59:24 2004 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,565 +0,0 @@ -/******************************************************************************* - - - Copyright(c) 1999 - 2003 Intel Corporation. All rights reserved. - - This program is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by the Free - Software Foundation; either version 2 of the License, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - this program; if not, write to the Free Software Foundation, Inc., 59 - Temple Place - Suite 330, Boston, MA 02111-1307, USA. - - The full GNU General Public License is included in this distribution in the - file called LICENSE. - - Contact Information: - Linux NICS - Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 -*******************************************************************************/ - -/********************************************************************** -* * -* INTEL CORPORATION * -* * -* This software is supplied under the terms of the license included * -* above. All use of this driver must be in accordance with the terms * -* of that license. * -* * -* Module Name: e100_eeprom.c * -* * -* Abstract: This module contains routines to read and write to a * -* serial EEPROM * -* * -* Environment: This file is intended to be specific to the Linux * -* operating system. * -* * -**********************************************************************/ -#include "e100.h" - -#define CSR_EEPROM_CONTROL_FIELD(bdp) ((bdp)->scb->scb_eprm_cntrl) - -#define CSR_GENERAL_CONTROL2_FIELD(bdp) \ - ((bdp)->scb->scb_ext.d102_scb.scb_gen_ctrl2) - -#define EEPROM_STALL_TIME 4 -#define EEPROM_CHECKSUM ((u16) 0xBABA) -#define EEPROM_MAX_WORD_SIZE 256 - -void e100_eeprom_cleanup(struct e100_private *adapter); -u16 e100_eeprom_calculate_chksum(struct e100_private *adapter); -static void e100_eeprom_write_word(struct e100_private *adapter, u16 reg, - u16 data); -void e100_eeprom_write_block(struct e100_private *adapter, u16 start, u16 *data, - u16 size); -u16 e100_eeprom_size(struct e100_private *adapter); -u16 e100_eeprom_read(struct e100_private *adapter, u16 reg); - -static void shift_out_bits(struct e100_private *adapter, u16 data, u16 count); -static u16 shift_in_bits(struct e100_private *adapter); -static void raise_clock(struct e100_private *adapter, u16 *x); -static void lower_clock(struct e100_private *adapter, u16 *x); -static u16 eeprom_wait_cmd_done(struct e100_private *adapter); -static void eeprom_stand_by(struct e100_private *adapter); - -//---------------------------------------------------------------------------------------- -// Procedure: eeprom_set_semaphore -// -// Description: This function set (write 1) Gamla EEPROM semaphore bit (bit 23 word 0x1C in the CSR). -// -// Arguments: -// Adapter - Adapter context -// -// Returns: true if success -// else return false -// -//---------------------------------------------------------------------------------------- - -inline u8 -eeprom_set_semaphore(struct e100_private *adapter) -{ - u16 data = 0; - unsigned long expiration_time = jiffies + HZ / 100 + 1; - - do { - // Get current value of General Control 2 - data = readb(&CSR_GENERAL_CONTROL2_FIELD(adapter)); - - // Set bit 23 word 0x1C in the CSR. - data |= SCB_GCR2_EEPROM_ACCESS_SEMAPHORE; - writeb(data, &CSR_GENERAL_CONTROL2_FIELD(adapter)); - - // Check to see if this bit set or not. - data = readb(&CSR_GENERAL_CONTROL2_FIELD(adapter)); - - if (data & SCB_GCR2_EEPROM_ACCESS_SEMAPHORE) { - return true; - } - - if (time_before(jiffies, expiration_time)) - yield(); - else - return false; - - } while (true); -} - -//---------------------------------------------------------------------------------------- -// Procedure: eeprom_reset_semaphore -// -// Description: This function reset (write 0) Gamla EEPROM semaphore bit -// (bit 23 word 0x1C in the CSR). -// -// Arguments: struct e100_private * adapter - Adapter context -//---------------------------------------------------------------------------------------- - -inline void -eeprom_reset_semaphore(struct e100_private *adapter) -{ - u16 data = 0; - - data = readb(&CSR_GENERAL_CONTROL2_FIELD(adapter)); - data &= ~(SCB_GCR2_EEPROM_ACCESS_SEMAPHORE); - writeb(data, &CSR_GENERAL_CONTROL2_FIELD(adapter)); -} - -//---------------------------------------------------------------------------------------- -// Procedure: e100_eeprom_size -// -// Description: This routine determines the size of the EEPROM. This value should be -// checked for validity - ie. is it too big or too small. The size returned -// is then passed to the read/write functions. -// -// Returns: -// Size of the eeprom, or zero if an error occurred -//---------------------------------------------------------------------------------------- -u16 -e100_eeprom_size(struct e100_private *adapter) -{ - u16 x, size = 1; // must be one to accumulate a product - - // if we've already stored this data, read from memory - if (adapter->eeprom_size) { - return adapter->eeprom_size; - } - // otherwise, read from the eeprom - // Set EEPROM semaphore. - if (adapter->rev_id >= D102_REV_ID) { - if (!eeprom_set_semaphore(adapter)) - return 0; - } - // enable the eeprom by setting EECS. - x = readw(&CSR_EEPROM_CONTROL_FIELD(adapter)); - x &= ~(EEDI | EEDO | EESK); - x |= EECS; - writew(x, &CSR_EEPROM_CONTROL_FIELD(adapter)); - - // write the read opcode - shift_out_bits(adapter, EEPROM_READ_OPCODE, 3); - - // experiment to discover the size of the eeprom. request register zero - // and wait for the eeprom to tell us it has accepted the entire address. - x = readw(&CSR_EEPROM_CONTROL_FIELD(adapter)); - do { - size *= 2; // each bit of address doubles eeprom size - x |= EEDO; // set bit to detect "dummy zero" - x &= ~EEDI; // address consists of all zeros - - writew(x, &CSR_EEPROM_CONTROL_FIELD(adapter)); - readw(&(adapter->scb->scb_status)); - udelay(EEPROM_STALL_TIME); - raise_clock(adapter, &x); - lower_clock(adapter, &x); - - // check for "dummy zero" - x = readw(&CSR_EEPROM_CONTROL_FIELD(adapter)); - if (size > EEPROM_MAX_WORD_SIZE) { - size = 0; - break; - } - } while (x & EEDO); - - // read in the value requested - (void) shift_in_bits(adapter); - e100_eeprom_cleanup(adapter); - - // Clear EEPROM Semaphore. - if (adapter->rev_id >= D102_REV_ID) { - eeprom_reset_semaphore(adapter); - } - - return size; -} - -//---------------------------------------------------------------------------------------- -// Procedure: eeprom_address_size -// -// Description: determines the number of bits in an address for the eeprom acceptable -// values are 64, 128, and 256 -// Arguments: size of the eeprom -// Returns: bits in an address for that size eeprom -//---------------------------------------------------------------------------------------- - -static inline int -eeprom_address_size(u16 size) -{ - int isize = size; - - return (ffs(isize) - 1); -} - -//---------------------------------------------------------------------------------------- -// Procedure: e100_eeprom_read -// -// Description: This routine serially reads one word out of the EEPROM. -// -// Arguments: -// adapter - our adapter context -// reg - EEPROM word to read. -// -// Returns: -// Contents of EEPROM word (reg). -//---------------------------------------------------------------------------------------- - -u16 -e100_eeprom_read(struct e100_private *adapter, u16 reg) -{ - u16 x, data, bits; - - // Set EEPROM semaphore. - if (adapter->rev_id >= D102_REV_ID) { - if (!eeprom_set_semaphore(adapter)) - return 0; - } - // eeprom size is initialized to zero - if (!adapter->eeprom_size) - adapter->eeprom_size = e100_eeprom_size(adapter); - - bits = eeprom_address_size(adapter->eeprom_size); - - // select EEPROM, reset bits, set EECS - x = readw(&CSR_EEPROM_CONTROL_FIELD(adapter)); - - x &= ~(EEDI | EEDO | EESK); - x |= EECS; - writew(x, &CSR_EEPROM_CONTROL_FIELD(adapter)); - - // write the read opcode and register number in that order - // The opcode is 3bits in length, reg is 'bits' bits long - shift_out_bits(adapter, EEPROM_READ_OPCODE, 3); - shift_out_bits(adapter, reg, bits); - - // Now read the data (16 bits) in from the selected EEPROM word - data = shift_in_bits(adapter); - - e100_eeprom_cleanup(adapter); - - // Clear EEPROM Semaphore. - if (adapter->rev_id >= D102_REV_ID) { - eeprom_reset_semaphore(adapter); - } - - return data; -} - -//---------------------------------------------------------------------------------------- -// Procedure: shift_out_bits -// -// Description: This routine shifts data bits out to the EEPROM. -// -// Arguments: -// data - data to send to the EEPROM. -// count - number of data bits to shift out. -// -// Returns: (none) -//---------------------------------------------------------------------------------------- - -static void -shift_out_bits(struct e100_private *adapter, u16 data, u16 count) -{ - u16 x, mask; - - mask = 1 << (count - 1); - x = readw(&CSR_EEPROM_CONTROL_FIELD(adapter)); - x &= ~(EEDO | EEDI); - - do { - x &= ~EEDI; - if (data & mask) - x |= EEDI; - - writew(x, &CSR_EEPROM_CONTROL_FIELD(adapter)); - readw(&(adapter->scb->scb_status)); /* flush command to card */ - udelay(EEPROM_STALL_TIME); - raise_clock(adapter, &x); - lower_clock(adapter, &x); - mask = mask >> 1; - } while (mask); - - x &= ~EEDI; - writew(x, &CSR_EEPROM_CONTROL_FIELD(adapter)); -} - -//---------------------------------------------------------------------------------------- -// Procedure: raise_clock -// -// Description: This routine raises the EEPROM's clock input (EESK) -// -// Arguments: -// x - Ptr to the EEPROM control register's current value -// -// Returns: (none) -//---------------------------------------------------------------------------------------- - -void -raise_clock(struct e100_private *adapter, u16 *x) -{ - *x = *x | EESK; - writew(*x, &CSR_EEPROM_CONTROL_FIELD(adapter)); - readw(&(adapter->scb->scb_status)); /* flush command to card */ - udelay(EEPROM_STALL_TIME); -} - -//---------------------------------------------------------------------------------------- -// Procedure: lower_clock -// -// Description: This routine lower's the EEPROM's clock input (EESK) -// -// Arguments: -// x - Ptr to the EEPROM control register's current value -// -// Returns: (none) -//---------------------------------------------------------------------------------------- - -void -lower_clock(struct e100_private *adapter, u16 *x) -{ - *x = *x & ~EESK; - writew(*x, &CSR_EEPROM_CONTROL_FIELD(adapter)); - readw(&(adapter->scb->scb_status)); /* flush command to card */ - udelay(EEPROM_STALL_TIME); -} - -//---------------------------------------------------------------------------------------- -// Procedure: shift_in_bits -// -// Description: This routine shifts data bits in from the EEPROM. -// -// Arguments: -// -// Returns: -// The contents of that particular EEPROM word -//---------------------------------------------------------------------------------------- - -static u16 -shift_in_bits(struct e100_private *adapter) -{ - u16 x, d, i; - - x = readw(&CSR_EEPROM_CONTROL_FIELD(adapter)); - x &= ~(EEDO | EEDI); - d = 0; - - for (i = 0; i < 16; i++) { - d <<= 1; - raise_clock(adapter, &x); - - x = readw(&CSR_EEPROM_CONTROL_FIELD(adapter)); - - x &= ~EEDI; - if (x & EEDO) - d |= 1; - - lower_clock(adapter, &x); - } - - return d; -} - -//---------------------------------------------------------------------------------------- -// Procedure: e100_eeprom_cleanup -// -// Description: This routine returns the EEPROM to an idle state -//---------------------------------------------------------------------------------------- - -void -e100_eeprom_cleanup(struct e100_private *adapter) -{ - u16 x; - - x = readw(&CSR_EEPROM_CONTROL_FIELD(adapter)); - - x &= ~(EECS | EEDI); - writew(x, &CSR_EEPROM_CONTROL_FIELD(adapter)); - - raise_clock(adapter, &x); - lower_clock(adapter, &x); -} - -//********************************************************************************** -// Procedure: e100_eeprom_update_chksum -// -// Description: Calculates the checksum and writes it to the EEProm. -// It calculates the checksum accroding to the formula: -// Checksum = 0xBABA - (sum of first 63 words). -// -//----------------------------------------------------------------------------------- -u16 -e100_eeprom_calculate_chksum(struct e100_private *adapter) -{ - u16 idx, xsum_index, checksum = 0; - - // eeprom size is initialized to zero - if (!adapter->eeprom_size) - adapter->eeprom_size = e100_eeprom_size(adapter); - - xsum_index = adapter->eeprom_size - 1; - for (idx = 0; idx < xsum_index; idx++) - checksum += e100_eeprom_read(adapter, idx); - - checksum = EEPROM_CHECKSUM - checksum; - return checksum; -} - -//---------------------------------------------------------------------------------------- -// Procedure: e100_eeprom_write_word -// -// Description: This routine writes a word to a specific EEPROM location without. -// taking EEPROM semaphore and updating checksum. -// Use e100_eeprom_write_block for the EEPROM update -// Arguments: reg - The EEPROM word that we are going to write to. -// data - The data (word) that we are going to write to the EEPROM. -//---------------------------------------------------------------------------------------- -static void -e100_eeprom_write_word(struct e100_private *adapter, u16 reg, u16 data) -{ - u16 x; - u16 bits; - - bits = eeprom_address_size(adapter->eeprom_size); - - /* select EEPROM, mask off ASIC and reset bits, set EECS */ - x = readw(&CSR_EEPROM_CONTROL_FIELD(adapter)); - x &= ~(EEDI | EEDO | EESK); - writew(x, &CSR_EEPROM_CONTROL_FIELD(adapter)); - readw(&(adapter->scb->scb_status)); /* flush command to card */ - udelay(EEPROM_STALL_TIME); - x |= EECS; - writew(x, &CSR_EEPROM_CONTROL_FIELD(adapter)); - - shift_out_bits(adapter, EEPROM_EWEN_OPCODE, 5); - shift_out_bits(adapter, reg, (u16) (bits - 2)); - if (!eeprom_wait_cmd_done(adapter)) - return; - - /* write the new word to the EEPROM & send the write opcode the EEPORM */ - shift_out_bits(adapter, EEPROM_WRITE_OPCODE, 3); - - /* select which word in the EEPROM that we are writing to */ - shift_out_bits(adapter, reg, bits); - - /* write the data to the selected EEPROM word */ - shift_out_bits(adapter, data, 16); - if (!eeprom_wait_cmd_done(adapter)) - return; - - shift_out_bits(adapter, EEPROM_EWDS_OPCODE, 5); - shift_out_bits(adapter, reg, (u16) (bits - 2)); - if (!eeprom_wait_cmd_done(adapter)) - return; - - e100_eeprom_cleanup(adapter); -} - -//---------------------------------------------------------------------------------------- -// Procedure: e100_eeprom_write_block -// -// Description: This routine writes a block of words starting from specified EEPROM -// location and updates checksum -// Arguments: reg - The EEPROM word that we are going to write to. -// data - The data (word) that we are going to write to the EEPROM. -//---------------------------------------------------------------------------------------- -void -e100_eeprom_write_block(struct e100_private *adapter, u16 start, u16 *data, - u16 size) -{ - u16 checksum; - u16 i; - - if (!adapter->eeprom_size) - adapter->eeprom_size = e100_eeprom_size(adapter); - - // Set EEPROM semaphore. - if (adapter->rev_id >= D102_REV_ID) { - if (!eeprom_set_semaphore(adapter)) - return; - } - - for (i = 0; i < size; i++) { - e100_eeprom_write_word(adapter, start + i, data[i]); - } - //Update checksum - checksum = e100_eeprom_calculate_chksum(adapter); - e100_eeprom_write_word(adapter, (adapter->eeprom_size - 1), checksum); - - // Clear EEPROM Semaphore. - if (adapter->rev_id >= D102_REV_ID) { - eeprom_reset_semaphore(adapter); - } -} - -//---------------------------------------------------------------------------------------- -// Procedure: eeprom_wait_cmd_done -// -// Description: This routine waits for the the EEPROM to finish its command. -// Specifically, it waits for EEDO (data out) to go high. -// Returns: true - If the command finished -// false - If the command never finished (EEDO stayed low) -//---------------------------------------------------------------------------------------- -static u16 -eeprom_wait_cmd_done(struct e100_private *adapter) -{ - u16 x; - unsigned long expiration_time = jiffies + HZ / 100 + 1; - - eeprom_stand_by(adapter); - - do { - rmb(); - x = readw(&CSR_EEPROM_CONTROL_FIELD(adapter)); - if (x & EEDO) - return true; - if (time_before(jiffies, expiration_time)) - yield(); - else - return false; - } while (true); -} - -//---------------------------------------------------------------------------------------- -// Procedure: eeprom_stand_by -// -// Description: This routine lowers the EEPROM chip select (EECS) for a few microseconds. -//---------------------------------------------------------------------------------------- -static void -eeprom_stand_by(struct e100_private *adapter) -{ - u16 x; - - x = readw(&CSR_EEPROM_CONTROL_FIELD(adapter)); - x &= ~(EECS | EESK); - writew(x, &CSR_EEPROM_CONTROL_FIELD(adapter)); - readw(&(adapter->scb->scb_status)); /* flush command to card */ - udelay(EEPROM_STALL_TIME); - x |= EECS; - writew(x, &CSR_EEPROM_CONTROL_FIELD(adapter)); - readw(&(adapter->scb->scb_status)); /* flush command to card */ - udelay(EEPROM_STALL_TIME); -} diff -Nru a/drivers/net/e100/e100_main.c b/drivers/net/e100/e100_main.c --- a/drivers/net/e100/e100_main.c Thu Jan 22 18:59:25 2004 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,4343 +0,0 @@ -/******************************************************************************* - - - Copyright(c) 1999 - 2003 Intel Corporation. All rights reserved. - - This program is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by the Free - Software Foundation; either version 2 of the License, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - this program; if not, write to the Free Software Foundation, Inc., 59 - Temple Place - Suite 330, Boston, MA 02111-1307, USA. - - The full GNU General Public License is included in this distribution in the - file called LICENSE. - - Contact Information: - Linux NICS - Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 -*******************************************************************************/ - -/********************************************************************** -* * -* INTEL CORPORATION * -* * -* This software is supplied under the terms of the license included * -* above. All use of this driver must be in accordance with the terms * -* of that license. * -* * -* Module Name: e100_main.c * -* * -* Abstract: Functions for the driver entry points like load, * -* unload, open and close. All board specific calls made * -* by the network interface section of the driver. * -* * -* Environment: This file is intended to be specific to the Linux * -* operating system. * -* * -**********************************************************************/ - -/* Change Log - * - * 2.3.30 09/21/03 - * o Bug fix (Bugzilla 97908): Loading e100 was causing crash on Itanium2 - * with HP chipset - * o Bug fix (Bugzilla 101583): e100 can't pass traffic with ipv6 - * o Bug fix (Bugzilla 101360): PRO/10+ can't pass traffic - * - * 2.3.27 08/08/03 - * o Bug fix: read skb->len after freeing skb - * [Andrew Morton] akpm@zip.com.au - * o Bug fix: 82557 (with National PHY) timeout during init - * [Adam Kropelin] akropel1@rochester.rr.com - * o Feature add: allow to change Wake On LAN when EEPROM disabled - * - * 2.3.13 05/08/03 - */ - -#include -#include -#include -#include -#include "e100.h" -#include "e100_ucode.h" -#include "e100_config.h" -#include "e100_phy.h" - -extern void e100_force_speed_duplex_to_phy(struct e100_private *bdp); - -static char e100_gstrings_stats[][ETH_GSTRING_LEN] = { - "rx_packets", "tx_packets", "rx_bytes", "tx_bytes", "rx_errors", - "tx_errors", "rx_dropped", "tx_dropped", "multicast", "collisions", - "rx_length_errors", "rx_over_errors", "rx_crc_errors", - "rx_frame_errors", "rx_fifo_errors", "rx_missed_errors", - "tx_aborted_errors", "tx_carrier_errors", "tx_fifo_errors", - "tx_heartbeat_errors", "tx_window_errors", -}; -#define E100_STATS_LEN sizeof(e100_gstrings_stats) / ETH_GSTRING_LEN - -static int e100_do_ethtool_ioctl(struct net_device *, struct ifreq *); -static void e100_get_speed_duplex_caps(struct e100_private *); -static int e100_ethtool_get_settings(struct net_device *, struct ifreq *); -static int e100_ethtool_set_settings(struct net_device *, struct ifreq *); - -static int e100_ethtool_get_drvinfo(struct net_device *, struct ifreq *); -static int e100_ethtool_eeprom(struct net_device *, struct ifreq *); - -#define E100_EEPROM_MAGIC 0x1234 -static int e100_ethtool_glink(struct net_device *, struct ifreq *); -static int e100_ethtool_gregs(struct net_device *, struct ifreq *); -static int e100_ethtool_nway_rst(struct net_device *, struct ifreq *); -static int e100_ethtool_wol(struct net_device *, struct ifreq *); -#ifdef CONFIG_PM -static unsigned char e100_setup_filter(struct e100_private *bdp); -static void e100_do_wol(struct pci_dev *pcid, struct e100_private *bdp); -#endif -static u16 e100_get_ip_lbytes(struct net_device *dev); -extern void e100_config_wol(struct e100_private *bdp); -extern u32 e100_run_diag(struct net_device *dev, u64 *test_info, u32 flags); -static int e100_ethtool_test(struct net_device *, struct ifreq *); -static int e100_ethtool_gstrings(struct net_device *, struct ifreq *); -static char test_strings[][ETH_GSTRING_LEN] = { - "Link test (on/offline)", - "Eeprom test (on/offline)", - "Self test (offline)", - "Mac loopback (offline)", - "Phy loopback (offline)", - "Cable diagnostic (offline)" -}; - -static int e100_ethtool_led_blink(struct net_device *, struct ifreq *); - -static int e100_mii_ioctl(struct net_device *, struct ifreq *, int); - -static unsigned char e100_delayed_exec_non_cu_cmd(struct e100_private *, - nxmit_cb_entry_t *); -static void e100_free_nontx_list(struct e100_private *); -static void e100_non_tx_background(unsigned long); -static inline void e100_tx_skb_free(struct e100_private *bdp, tcb_t *tcb); -/* Global Data structures and variables */ -char e100_copyright[] = "Copyright (c) 2003 Intel Corporation"; -char e100_driver_version[]="2.3.30-k1"; -const char *e100_full_driver_name = "Intel(R) PRO/100 Network Driver"; -char e100_short_driver_name[] = "e100"; -static int e100nics = 0; -static void e100_vlan_rx_register(struct net_device *netdev, struct vlan_group - *grp); -static void e100_vlan_rx_add_vid(struct net_device *netdev, u16 vid); -static void e100_vlan_rx_kill_vid(struct net_device *netdev, u16 vid); - -#ifdef CONFIG_PM -static int e100_notify_reboot(struct notifier_block *, unsigned long event, void *ptr); -static int e100_suspend(struct pci_dev *pcid, u32 state); -static int e100_resume(struct pci_dev *pcid); -static unsigned char e100_asf_enabled(struct e100_private *bdp); -struct notifier_block e100_notifier_reboot = { - .notifier_call = e100_notify_reboot, - .next = NULL, - .priority = 0 -}; -#endif - -/*********************************************************************/ -/*! This is a GCC extension to ANSI C. - * See the item "Labeled Elements in Initializers" in the section - * "Extensions to the C Language Family" of the GCC documentation. - *********************************************************************/ -#define E100_PARAM_INIT { [0 ... E100_MAX_NIC] = -1 } - -/* All parameters are treated the same, as an integer array of values. - * This macro just reduces the need to repeat the same declaration code - * over and over (plus this helps to avoid typo bugs). - */ -#define E100_PARAM(X, S) \ - static const int X[E100_MAX_NIC + 1] = E100_PARAM_INIT; \ - MODULE_PARM(X, "1-" __MODULE_STRING(E100_MAX_NIC) "i"); \ - MODULE_PARM_DESC(X, S); - -/* ====================================================================== */ -static u8 e100_D101M_checksum(struct e100_private *, struct sk_buff *); -static u8 e100_D102_check_checksum(rfd_t *); -static int e100_ioctl(struct net_device *, struct ifreq *, int); -static int e100_change_mtu(struct net_device *, int); -static int e100_xmit_frame(struct sk_buff *, struct net_device *); -static unsigned char e100_init(struct e100_private *); -static int e100_set_mac(struct net_device *, void *); -struct net_device_stats *e100_get_stats(struct net_device *); - -static irqreturn_t e100intr(int, void *, struct pt_regs *); -static void e100_print_brd_conf(struct e100_private *); -static void e100_set_multi(struct net_device *); - -static u8 e100_pci_setup(struct pci_dev *, struct e100_private *); -static u8 e100_sw_init(struct e100_private *); -static void e100_tco_workaround(struct e100_private *); -static unsigned char e100_alloc_space(struct e100_private *); -static void e100_dealloc_space(struct e100_private *); -static int e100_alloc_tcb_pool(struct e100_private *); -static void e100_setup_tcb_pool(tcb_t *, unsigned int, struct e100_private *); -static void e100_free_tcb_pool(struct e100_private *); -static int e100_alloc_rfd_pool(struct e100_private *); -static void e100_free_rfd_pool(struct e100_private *); - -static void e100_rd_eaddr(struct e100_private *); -static void e100_rd_pwa_no(struct e100_private *); -extern u16 e100_eeprom_read(struct e100_private *, u16); -extern void e100_eeprom_write_block(struct e100_private *, u16, u16 *, u16); -extern u16 e100_eeprom_size(struct e100_private *); -u16 e100_eeprom_calculate_chksum(struct e100_private *adapter); - -static unsigned char e100_clr_cntrs(struct e100_private *); -static unsigned char e100_load_microcode(struct e100_private *); -static unsigned char e100_setup_iaaddr(struct e100_private *, u8 *); -static unsigned char e100_update_stats(struct e100_private *bdp); - -static void e100_start_ru(struct e100_private *); -static void e100_dump_stats_cntrs(struct e100_private *); - -static void e100_check_options(int board, struct e100_private *bdp); -static void e100_set_int_option(int *, int, int, int, int, char *); -static void e100_set_bool_option(struct e100_private *bdp, int, u32, int, - char *); -unsigned char e100_wait_exec_cmplx(struct e100_private *, u32, u8, u8); -void e100_exec_cmplx(struct e100_private *, u32, u8); - -/** - * e100_get_rx_struct - retrieve cell to hold skb buff from the pool - * @bdp: atapter's private data struct - * - * Returns the new cell to hold sk_buff or %NULL. - */ -static inline struct rx_list_elem * -e100_get_rx_struct(struct e100_private *bdp) -{ - struct rx_list_elem *rx_struct = NULL; - - if (!list_empty(&(bdp->rx_struct_pool))) { - rx_struct = list_entry(bdp->rx_struct_pool.next, - struct rx_list_elem, list_elem); - list_del(&(rx_struct->list_elem)); - } - - return rx_struct; -} - -/** - * e100_alloc_skb - allocate an skb for the adapter - * @bdp: atapter's private data struct - * - * Allocates skb with enough room for rfd, and data, and reserve non-data space. - * Returns the new cell with sk_buff or %NULL. - */ -static inline struct rx_list_elem * -e100_alloc_skb(struct e100_private *bdp) -{ - struct sk_buff *new_skb; - u32 skb_size = sizeof (rfd_t); - struct rx_list_elem *rx_struct; - - new_skb = (struct sk_buff *) dev_alloc_skb(skb_size); - if (new_skb) { - /* The IP data should be - DWORD aligned. since the ethernet header is 14 bytes long, - we need to reserve 2 extra bytes so that the TCP/IP headers - will be DWORD aligned. */ - skb_reserve(new_skb, 2); - if ((rx_struct = e100_get_rx_struct(bdp)) == NULL) - goto err; - rx_struct->skb = new_skb; - rx_struct->dma_addr = pci_map_single(bdp->pdev, new_skb->data, - sizeof (rfd_t), - PCI_DMA_FROMDEVICE); - if (!rx_struct->dma_addr) - goto err; - skb_reserve(new_skb, bdp->rfd_size); - return rx_struct; - } else { - return NULL; - } - -err: - dev_kfree_skb_irq(new_skb); - return NULL; -} - -/** - * e100_add_skb_to_end - add an skb to the end of our rfd list - * @bdp: atapter's private data struct - * @rx_struct: rx_list_elem with the new skb - * - * Adds a newly allocated skb to the end of our rfd list. - */ -inline void -e100_add_skb_to_end(struct e100_private *bdp, struct rx_list_elem *rx_struct) -{ - rfd_t *rfdn; /* The new rfd */ - rfd_t *rfd; /* The old rfd */ - struct rx_list_elem *rx_struct_last; - - (rx_struct->skb)->dev = bdp->device; - rfdn = RFD_POINTER(rx_struct->skb, bdp); - rfdn->rfd_header.cb_status = 0; - rfdn->rfd_header.cb_cmd = __constant_cpu_to_le16(RFD_EL_BIT); - rfdn->rfd_act_cnt = 0; - rfdn->rfd_sz = __constant_cpu_to_le16(RFD_DATA_SIZE); - - pci_dma_sync_single(bdp->pdev, rx_struct->dma_addr, bdp->rfd_size, - PCI_DMA_TODEVICE); - - if (!list_empty(&(bdp->active_rx_list))) { - rx_struct_last = list_entry(bdp->active_rx_list.prev, - struct rx_list_elem, list_elem); - rfd = RFD_POINTER(rx_struct_last->skb, bdp); - pci_dma_sync_single(bdp->pdev, rx_struct_last->dma_addr, - 4, PCI_DMA_FROMDEVICE); - put_unaligned(cpu_to_le32(rx_struct->dma_addr), - ((u32 *) (&(rfd->rfd_header.cb_lnk_ptr)))); - - pci_dma_sync_single(bdp->pdev, rx_struct_last->dma_addr, - 8, PCI_DMA_TODEVICE); - rfd->rfd_header.cb_cmd &= - __constant_cpu_to_le16((u16) ~RFD_EL_BIT); - - pci_dma_sync_single(bdp->pdev, rx_struct_last->dma_addr, - 4, PCI_DMA_TODEVICE); - } - - list_add_tail(&(rx_struct->list_elem), &(bdp->active_rx_list)); -} - -static inline void -e100_alloc_skbs(struct e100_private *bdp) -{ - for (; bdp->skb_req > 0; bdp->skb_req--) { - struct rx_list_elem *rx_struct; - - if ((rx_struct = e100_alloc_skb(bdp)) == NULL) - return; - - e100_add_skb_to_end(bdp, rx_struct); - } -} - -void e100_tx_srv(struct e100_private *); -u32 e100_rx_srv(struct e100_private *); - -void e100_watchdog(struct net_device *); -void e100_refresh_txthld(struct e100_private *); -void e100_manage_adaptive_ifs(struct e100_private *); -void e100_clear_pools(struct e100_private *); -static void e100_clear_structs(struct net_device *); -static inline tcb_t *e100_prepare_xmit_buff(struct e100_private *, - struct sk_buff *); -static void e100_set_multi_exec(struct net_device *dev); - -MODULE_AUTHOR("Intel Corporation, "); -MODULE_DESCRIPTION("Intel(R) PRO/100 Network Driver"); -MODULE_LICENSE("GPL"); - -E100_PARAM(TxDescriptors, "Number of transmit descriptors"); -E100_PARAM(RxDescriptors, "Number of receive descriptors"); -E100_PARAM(XsumRX, "Disable or enable Receive Checksum offload"); -E100_PARAM(e100_speed_duplex, "Speed and Duplex settings"); -E100_PARAM(ucode, "Disable or enable microcode loading"); -E100_PARAM(ber, "Value for the BER correction algorithm"); -E100_PARAM(flow_control, "Disable or enable Ethernet PAUSE frames processing"); -E100_PARAM(IntDelay, "Value for CPU saver's interrupt delay"); -E100_PARAM(BundleSmallFr, "Disable or enable interrupt bundling of small frames"); -E100_PARAM(BundleMax, "Maximum number for CPU saver's packet bundling"); -E100_PARAM(IFS, "Disable or enable the adaptive IFS algorithm"); - -/** - * e100_exec_cmd - issue a comand - * @bdp: atapter's private data struct - * @scb_cmd_low: the command that is to be issued - * - * This general routine will issue a command to the e100. - */ -static inline void -e100_exec_cmd(struct e100_private *bdp, u8 cmd_low) -{ - writeb(cmd_low, &(bdp->scb->scb_cmd_low)); - readw(&(bdp->scb->scb_status)); /* flushes last write, read-safe */ -} - -/** - * e100_wait_scb - wait for SCB to clear - * @bdp: atapter's private data struct - * - * This routine checks to see if the e100 has accepted a command. - * It does so by checking the command field in the SCB, which will - * be zeroed by the e100 upon accepting a command. The loop waits - * for up to 1 millisecond for command acceptance. - * - * Returns: - * true if the SCB cleared within 1 millisecond. - * false if it didn't clear within 1 millisecond - */ -unsigned char -e100_wait_scb(struct e100_private *bdp) -{ - int i; - - /* loop on the scb for a few times */ - for (i = 0; i < 100; i++) { - if (!readb(&bdp->scb->scb_cmd_low)) - return true; - cpu_relax(); - } - - /* it didn't work. do it the slow way using udelay()s */ - for (i = 0; i < E100_MAX_SCB_WAIT; i++) { - if (!readb(&bdp->scb->scb_cmd_low)) - return true; - cpu_relax(); - udelay(1); - } - - return false; -} - -/** - * e100_wait_exec_simple - issue a command - * @bdp: atapter's private data struct - * @scb_cmd_low: the command that is to be issued - * - * This general routine will issue a command to the e100 after waiting for - * the previous command to finish. - * - * Returns: - * true if the command was issued to the chip successfully - * false if the command was not issued to the chip - */ -inline unsigned char -e100_wait_exec_simple(struct e100_private *bdp, u8 scb_cmd_low) -{ - if (!e100_wait_scb(bdp)) { - printk(KERN_DEBUG "e100: %s: e100_wait_exec_simple: failed\n", - bdp->device->name); -#ifdef E100_CU_DEBUG - printk(KERN_ERR "e100: %s: Last command (%x/%x) " - "timeout\n", bdp->device->name, - bdp->last_cmd, bdp->last_sub_cmd); - printk(KERN_ERR "e100: %s: Current simple command (%x) " - "can't be executed\n", - bdp->device->name, scb_cmd_low); -#endif - return false; - } - e100_exec_cmd(bdp, scb_cmd_low); -#ifdef E100_CU_DEBUG - bdp->last_cmd = scb_cmd_low; - bdp->last_sub_cmd = 0; -#endif - return true; -} - -void -e100_exec_cmplx(struct e100_private *bdp, u32 phys_addr, u8 cmd) -{ - writel(phys_addr, &(bdp->scb->scb_gen_ptr)); - readw(&(bdp->scb->scb_status)); /* flushes last write, read-safe */ - e100_exec_cmd(bdp, cmd); -} - -unsigned char -e100_wait_exec_cmplx(struct e100_private *bdp, u32 phys_addr, u8 cmd, u8 sub_cmd) -{ - if (!e100_wait_scb(bdp)) { -#ifdef E100_CU_DEBUG - printk(KERN_ERR "e100: %s: Last command (%x/%x) " - "timeout\n", bdp->device->name, - bdp->last_cmd, bdp->last_sub_cmd); - printk(KERN_ERR "e100: %s: Current complex command " - "(%x/%x) can't be executed\n", - bdp->device->name, cmd, sub_cmd); -#endif - return false; - } - e100_exec_cmplx(bdp, phys_addr, cmd); -#ifdef E100_CU_DEBUG - bdp->last_cmd = cmd; - bdp->last_sub_cmd = sub_cmd; -#endif - return true; -} - -inline u8 -e100_wait_cus_idle(struct e100_private *bdp) -{ - int i; - - /* loop on the scb for a few times */ - for (i = 0; i < 100; i++) { - if (((readw(&(bdp->scb->scb_status)) & SCB_CUS_MASK) != - SCB_CUS_ACTIVE)) { - return true; - } - cpu_relax(); - } - - for (i = 0; i < E100_MAX_CU_IDLE_WAIT; i++) { - if (((readw(&(bdp->scb->scb_status)) & SCB_CUS_MASK) != - SCB_CUS_ACTIVE)) { - return true; - } - cpu_relax(); - udelay(1); - } - - return false; -} - -/** - * e100_disable_clear_intr - disable and clear/ack interrupts - * @bdp: atapter's private data struct - * - * This routine disables interrupts at the hardware, by setting - * the M (mask) bit in the adapter's CSR SCB command word. - * It also clear/ack interrupts. - */ -static inline void -e100_disable_clear_intr(struct e100_private *bdp) -{ - u16 intr_status; - /* Disable interrupts on our PCI board by setting the mask bit */ - writeb(SCB_INT_MASK, &bdp->scb->scb_cmd_hi); - intr_status = readw(&bdp->scb->scb_status); - /* ack and clear intrs */ - writew(intr_status, &bdp->scb->scb_status); - readw(&bdp->scb->scb_status); -} - -/** - * e100_set_intr_mask - set interrupts - * @bdp: atapter's private data struct - * - * This routine sets interrupts at the hardware, by resetting - * the M (mask) bit in the adapter's CSR SCB command word - */ -static inline void -e100_set_intr_mask(struct e100_private *bdp) -{ - writeb(bdp->intr_mask, &bdp->scb->scb_cmd_hi); - readw(&(bdp->scb->scb_status)); /* flushes last write, read-safe */ -} - -static inline void -e100_trigger_SWI(struct e100_private *bdp) -{ - /* Trigger interrupt on our PCI board by asserting SWI bit */ - writeb(SCB_SOFT_INT, &bdp->scb->scb_cmd_hi); - readw(&(bdp->scb->scb_status)); /* flushes last write, read-safe */ -} - -static int -e100_found1(struct pci_dev *pcid, const struct pci_device_id *ent) -{ - static int first_time = true; - struct net_device *dev = NULL; - struct e100_private *bdp = NULL; - int rc = 0; - u16 cal_checksum, read_checksum; - - dev = alloc_etherdev(sizeof (struct e100_private)); - if (dev == NULL) { - printk(KERN_ERR "e100: Not able to alloc etherdev struct\n"); - rc = -ENODEV; - goto out; - } - - SET_MODULE_OWNER(dev); - - if (first_time) { - first_time = false; - printk(KERN_NOTICE "%s - version %s\n", - e100_full_driver_name, e100_driver_version); - printk(KERN_NOTICE "%s\n", e100_copyright); - printk(KERN_NOTICE "\n"); - } - - bdp = dev->priv; - bdp->pdev = pcid; - bdp->device = dev; - - pci_set_drvdata(pcid, dev); - SET_NETDEV_DEV(dev, &pcid->dev); - - bdp->flags = 0; - bdp->ifs_state = 0; - bdp->ifs_value = 0; - bdp->scb = 0; - - init_timer(&bdp->nontx_timer_id); - bdp->nontx_timer_id.data = (unsigned long) bdp; - bdp->nontx_timer_id.function = (void *) &e100_non_tx_background; - INIT_LIST_HEAD(&(bdp->non_tx_cmd_list)); - bdp->non_tx_command_state = E100_NON_TX_IDLE; - - init_timer(&bdp->watchdog_timer); - bdp->watchdog_timer.data = (unsigned long) dev; - bdp->watchdog_timer.function = (void *) &e100_watchdog; - - if ((rc = e100_pci_setup(pcid, bdp)) != 0) { - goto err_dev; - } - - if ((rc = e100_alloc_space(bdp)) != 0) { - goto err_pci; - } - - if (((bdp->pdev->device > 0x1030) - && (bdp->pdev->device < 0x103F)) - || ((bdp->pdev->device >= 0x1050) - && (bdp->pdev->device <= 0x1057)) - || (bdp->pdev->device == 0x2449) - || (bdp->pdev->device == 0x2459) - || (bdp->pdev->device == 0x245D)) { - bdp->rev_id = D101MA_REV_ID; /* workaround for ICH3 */ - bdp->flags |= IS_ICH; - } - - if (bdp->rev_id == 0xff) - bdp->rev_id = 1; - - if ((u8) bdp->rev_id >= D101A4_REV_ID) - bdp->flags |= IS_BACHELOR; - - if ((u8) bdp->rev_id >= D102_REV_ID) { - bdp->flags |= USE_IPCB; - bdp->rfd_size = 32; - } else { - bdp->rfd_size = 16; - } - - dev->vlan_rx_register = e100_vlan_rx_register; - dev->vlan_rx_add_vid = e100_vlan_rx_add_vid; - dev->vlan_rx_kill_vid = e100_vlan_rx_kill_vid; - dev->irq = pcid->irq; - dev->open = &e100_open; - dev->hard_start_xmit = &e100_xmit_frame; - dev->stop = &e100_close; - dev->change_mtu = &e100_change_mtu; - dev->get_stats = &e100_get_stats; - dev->set_multicast_list = &e100_set_multi; - dev->set_mac_address = &e100_set_mac; - dev->do_ioctl = &e100_ioctl; - - if (bdp->flags & USE_IPCB) - dev->features = NETIF_F_SG | NETIF_F_IP_CSUM | - NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX; - - if ((rc = register_netdev(dev)) != 0) { - goto err_dealloc; - } - - e100_check_options(e100nics, bdp); - - if (!e100_init(bdp)) { - printk(KERN_ERR "e100: Failed to initialize, instance #%d\n", - e100nics); - rc = -ENODEV; - goto err_unregister_netdev; - } - - /* Check if checksum is valid */ - cal_checksum = e100_eeprom_calculate_chksum(bdp); - read_checksum = e100_eeprom_read(bdp, (bdp->eeprom_size - 1)); - if (cal_checksum != read_checksum) { - printk(KERN_ERR "e100: Corrupted EEPROM on instance #%d\n", - e100nics); - rc = -ENODEV; - goto err_unregister_netdev; - } - - e100nics++; - - e100_get_speed_duplex_caps(bdp); - - printk(KERN_NOTICE - "e100: %s: %s\n", - bdp->device->name, "Intel(R) PRO/100 Network Connection"); - e100_print_brd_conf(bdp); - - bdp->wolsupported = 0; - bdp->wolopts = 0; - if (bdp->rev_id >= D101A4_REV_ID) - bdp->wolsupported = WAKE_PHY | WAKE_MAGIC; - if (bdp->rev_id >= D101MA_REV_ID) - bdp->wolsupported |= WAKE_UCAST | WAKE_ARP; - - /* Check if WoL is enabled on EEPROM */ - if (e100_eeprom_read(bdp, EEPROM_ID_WORD) & BIT_5) { - /* Magic Packet WoL is enabled on device by default */ - /* if EEPROM WoL bit is TRUE */ - bdp->wolopts = WAKE_MAGIC; - } - - printk(KERN_NOTICE "\n"); - - goto out; - -err_unregister_netdev: - unregister_netdev(dev); -err_dealloc: - e100_dealloc_space(bdp); -err_pci: - iounmap(bdp->scb); - pci_release_regions(pcid); - pci_disable_device(pcid); -err_dev: - pci_set_drvdata(pcid, NULL); - kfree(dev); -out: - return rc; -} - -/** - * e100_clear_structs - free resources - * @dev: adapter's net_device struct - * - * Free all device specific structs, unmap i/o address, etc. - */ -static void __devexit -e100_clear_structs(struct net_device *dev) -{ - struct e100_private *bdp = dev->priv; - - iounmap(bdp->scb); - pci_release_regions(bdp->pdev); - pci_disable_device(bdp->pdev); - - e100_dealloc_space(bdp); - pci_set_drvdata(bdp->pdev, NULL); - free_netdev(dev); -} - -static void __devexit -e100_remove1(struct pci_dev *pcid) -{ - struct net_device *dev; - struct e100_private *bdp; - - if (!(dev = (struct net_device *) pci_get_drvdata(pcid))) - return; - - bdp = dev->priv; - - unregister_netdev(dev); - - e100_sw_reset(bdp, PORT_SELECTIVE_RESET); - - if (bdp->non_tx_command_state != E100_NON_TX_IDLE) { - del_timer_sync(&bdp->nontx_timer_id); - e100_free_nontx_list(bdp); - bdp->non_tx_command_state = E100_NON_TX_IDLE; - } - - e100_clear_structs(dev); - - --e100nics; -} - -static struct pci_device_id e100_id_table[] = { - {0x8086, 0x1229, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, - {0x8086, 0x2449, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, - {0x8086, 0x1059, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, - {0x8086, 0x1209, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, - {0x8086, 0x1029, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, - {0x8086, 0x1030, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, - {0x8086, 0x1031, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, - {0x8086, 0x1032, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, - {0x8086, 0x1033, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, - {0x8086, 0x1034, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, - {0x8086, 0x1038, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, - {0x8086, 0x1039, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, - {0x8086, 0x103A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, - {0x8086, 0x103B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, - {0x8086, 0x103C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, - {0x8086, 0x103D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, - {0x8086, 0x103E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, - {0x8086, 0x1050, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, - {0x8086, 0x1051, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, - {0x8086, 0x1052, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, - {0x8086, 0x1053, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, - {0x8086, 0x1054, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, - {0x8086, 0x1055, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, - {0x8086, 0x2459, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, - {0x8086, 0x245D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, - {0,} /* This has to be the last entry*/ -}; -MODULE_DEVICE_TABLE(pci, e100_id_table); - -static struct pci_driver e100_driver = { - .name = "e100", - .id_table = e100_id_table, - .probe = e100_found1, - .remove = __devexit_p(e100_remove1), -#ifdef CONFIG_PM - .suspend = e100_suspend, - .resume = e100_resume, -#endif -}; - -static int __init -e100_init_module(void) -{ - int ret; - ret = pci_module_init(&e100_driver); - - if(ret >= 0) { -#ifdef CONFIG_PM - register_reboot_notifier(&e100_notifier_reboot); -#endif - } - - return ret; -} - -static void __exit -e100_cleanup_module(void) -{ -#ifdef CONFIG_PM - unregister_reboot_notifier(&e100_notifier_reboot); -#endif - - pci_unregister_driver(&e100_driver); -} - -module_init(e100_init_module); -module_exit(e100_cleanup_module); - -/** - * e100_check_options - check command line options - * @board: board number - * @bdp: atapter's private data struct - * - * This routine does range checking on command-line options - */ -void -e100_check_options(int board, struct e100_private *bdp) -{ - if (board >= E100_MAX_NIC) { - printk(KERN_NOTICE - "e100: No configuration available for board #%d\n", - board); - printk(KERN_NOTICE "e100: Using defaults for all values\n"); - board = E100_MAX_NIC; - } - - e100_set_int_option(&(bdp->params.TxDescriptors), TxDescriptors[board], - E100_MIN_TCB, E100_MAX_TCB, E100_DEFAULT_TCB, - "TxDescriptor count"); - - e100_set_int_option(&(bdp->params.RxDescriptors), RxDescriptors[board], - E100_MIN_RFD, E100_MAX_RFD, E100_DEFAULT_RFD, - "RxDescriptor count"); - - e100_set_int_option(&(bdp->params.e100_speed_duplex), - e100_speed_duplex[board], 0, 4, - E100_DEFAULT_SPEED_DUPLEX, "speed/duplex mode"); - - e100_set_int_option(&(bdp->params.ber), ber[board], 0, ZLOCK_MAX_ERRORS, - E100_DEFAULT_BER, "Bit Error Rate count"); - - e100_set_bool_option(bdp, XsumRX[board], PRM_XSUMRX, E100_DEFAULT_XSUM, - "XsumRX value"); - - /* Default ucode value depended on controller revision */ - if (bdp->rev_id >= D101MA_REV_ID) { - e100_set_bool_option(bdp, ucode[board], PRM_UCODE, - E100_DEFAULT_UCODE, "ucode value"); - } else { - e100_set_bool_option(bdp, ucode[board], PRM_UCODE, false, - "ucode value"); - } - - e100_set_bool_option(bdp, flow_control[board], PRM_FC, E100_DEFAULT_FC, - "flow control value"); - - e100_set_bool_option(bdp, IFS[board], PRM_IFS, E100_DEFAULT_IFS, - "IFS value"); - - e100_set_bool_option(bdp, BundleSmallFr[board], PRM_BUNDLE_SMALL, - E100_DEFAULT_BUNDLE_SMALL_FR, - "CPU saver bundle small frames value"); - - e100_set_int_option(&(bdp->params.IntDelay), IntDelay[board], 0x0, - 0xFFFF, E100_DEFAULT_CPUSAVER_INTERRUPT_DELAY, - "CPU saver interrupt delay value"); - - e100_set_int_option(&(bdp->params.BundleMax), BundleMax[board], 0x1, - 0xFFFF, E100_DEFAULT_CPUSAVER_BUNDLE_MAX, - "CPU saver bundle max value"); - -} - -/** - * e100_set_int_option - check and set an integer option - * @option: a pointer to the relevant option field - * @val: the value specified - * @min: the minimum valid value - * @max: the maximum valid value - * @default_val: the default value - * @name: the name of the option - * - * This routine does range checking on a command-line option. - * If the option's value is '-1' use the specified default. - * Otherwise, if the value is invalid, change it to the default. - */ -void -e100_set_int_option(int *option, int val, int min, int max, int default_val, - char *name) -{ - if (val == -1) { /* no value specified. use default */ - *option = default_val; - - } else if ((val < min) || (val > max)) { - printk(KERN_NOTICE - "e100: Invalid %s specified (%i). " - "Valid range is %i-%i\n", - name, val, min, max); - printk(KERN_NOTICE "e100: Using default %s of %i\n", name, - default_val); - *option = default_val; - } else { - printk(KERN_INFO "e100: Using specified %s of %i\n", name, val); - *option = val; - } -} - -/** - * e100_set_bool_option - check and set a boolean option - * @bdp: atapter's private data struct - * @val: the value specified - * @mask: the mask for the relevant option - * @default_val: the default value - * @name: the name of the option - * - * This routine checks a boolean command-line option. - * If the option's value is '-1' use the specified default. - * Otherwise, if the value is invalid (not 0 or 1), - * change it to the default. - */ -void -e100_set_bool_option(struct e100_private *bdp, int val, u32 mask, - int default_val, char *name) -{ - if (val == -1) { - if (default_val) - bdp->params.b_params |= mask; - - } else if ((val != true) && (val != false)) { - printk(KERN_NOTICE - "e100: Invalid %s specified (%i). " - "Valid values are %i/%i\n", - name, val, false, true); - printk(KERN_NOTICE "e100: Using default %s of %i\n", name, - default_val); - - if (default_val) - bdp->params.b_params |= mask; - } else { - printk(KERN_INFO "e100: Using specified %s of %i\n", name, val); - if (val) - bdp->params.b_params |= mask; - } -} - -int -e100_open(struct net_device *dev) -{ - struct e100_private *bdp; - int rc = 0; - - bdp = dev->priv; - - /* setup the tcb pool */ - if (!e100_alloc_tcb_pool(bdp)) { - rc = -ENOMEM; - goto err_exit; - } - bdp->last_tcb = NULL; - - bdp->tcb_pool.head = 0; - bdp->tcb_pool.tail = 1; - - e100_setup_tcb_pool((tcb_t *) bdp->tcb_pool.data, - bdp->params.TxDescriptors, bdp); - - if (!e100_alloc_rfd_pool(bdp)) { - rc = -ENOMEM; - goto err_exit; - } - - if (!e100_wait_exec_cmplx(bdp, 0, SCB_CUC_LOAD_BASE, 0)) { - rc = -EAGAIN; - goto err_exit; - } - - if (!e100_wait_exec_cmplx(bdp, 0, SCB_RUC_LOAD_BASE, 0)) { - rc = -EAGAIN; - goto err_exit; - } - - mod_timer(&(bdp->watchdog_timer), jiffies + (2 * HZ)); - - if (dev->flags & IFF_UP) - /* Otherwise process may sleep forever */ - netif_wake_queue(dev); - else - netif_start_queue(dev); - - e100_start_ru(bdp); - if ((rc = request_irq(dev->irq, &e100intr, SA_SHIRQ, - dev->name, dev)) != 0) { - del_timer_sync(&bdp->watchdog_timer); - goto err_exit; - } - bdp->intr_mask = 0; - e100_set_intr_mask(bdp); - - e100_force_config(bdp); - - goto exit; - -err_exit: - e100_clear_pools(bdp); -exit: - return rc; -} - -int -e100_close(struct net_device *dev) -{ - struct e100_private *bdp = dev->priv; - - e100_disable_clear_intr(bdp); - free_irq(dev->irq, dev); - bdp->intr_mask = SCB_INT_MASK; - e100_isolate_driver(bdp); - - netif_carrier_off(bdp->device); - bdp->cur_line_speed = 0; - bdp->cur_dplx_mode = 0; - e100_clear_pools(bdp); - - return 0; -} - -static int -e100_change_mtu(struct net_device *dev, int new_mtu) -{ - if ((new_mtu < 68) || (new_mtu > (ETH_DATA_LEN + VLAN_SIZE))) - return -EINVAL; - - dev->mtu = new_mtu; - return 0; -} - -static int -e100_xmit_frame(struct sk_buff *skb, struct net_device *dev) -{ - int rc = 0; - int notify_stop = false; - struct e100_private *bdp = dev->priv; - - if (!spin_trylock(&bdp->bd_non_tx_lock)) { - notify_stop = true; - rc = 1; - goto exit2; - } - - /* tcb list may be empty temporarily during releasing resources */ - if (!TCBS_AVAIL(bdp->tcb_pool) || (bdp->tcb_phys == 0) || - (bdp->non_tx_command_state != E100_NON_TX_IDLE)) { - notify_stop = true; - rc = 1; - goto exit1; - } - - bdp->drv_stats.net_stats.tx_bytes += skb->len; - - e100_prepare_xmit_buff(bdp, skb); - - dev->trans_start = jiffies; - -exit1: - spin_unlock(&bdp->bd_non_tx_lock); -exit2: - if (notify_stop) { - netif_stop_queue(dev); - } - - return rc; -} - -/** - * e100_get_stats - get driver statistics - * @dev: adapter's net_device struct - * - * This routine is called when the OS wants the adapter's stats returned. - * It returns the address of the net_device_stats stucture for the device. - * If the statistics are currently being updated, then they might be incorrect - * for a short while. However, since this cannot actually cause damage, no - * locking is used. - */ -struct net_device_stats * -e100_get_stats(struct net_device *dev) -{ - struct e100_private *bdp = dev->priv; - - bdp->drv_stats.net_stats.tx_errors = - bdp->drv_stats.net_stats.tx_carrier_errors + - bdp->drv_stats.net_stats.tx_aborted_errors; - - bdp->drv_stats.net_stats.rx_errors = - bdp->drv_stats.net_stats.rx_crc_errors + - bdp->drv_stats.net_stats.rx_frame_errors + - bdp->drv_stats.net_stats.rx_length_errors + - bdp->drv_stats.rcv_cdt_frames; - - return &(bdp->drv_stats.net_stats); -} - -/** - * e100_set_mac - set the MAC address - * @dev: adapter's net_device struct - * @addr: the new address - * - * This routine sets the ethernet address of the board - * Returns: - * 0 - if successful - * -1 - otherwise - */ -static int -e100_set_mac(struct net_device *dev, void *addr) -{ - struct e100_private *bdp; - int rc = -1; - struct sockaddr *p_sockaddr = (struct sockaddr *) addr; - - if (!is_valid_ether_addr(p_sockaddr->sa_data)) - return -EADDRNOTAVAIL; - bdp = dev->priv; - - if (e100_setup_iaaddr(bdp, (u8 *) (p_sockaddr->sa_data))) { - memcpy(&(dev->dev_addr[0]), p_sockaddr->sa_data, ETH_ALEN); - rc = 0; - } - - return rc; -} - -static void -e100_set_multi_exec(struct net_device *dev) -{ - struct e100_private *bdp = dev->priv; - mltcst_cb_t *mcast_buff; - cb_header_t *cb_hdr; - struct dev_mc_list *mc_list; - unsigned int i; - nxmit_cb_entry_t *cmd = e100_alloc_non_tx_cmd(bdp); - - if (cmd != NULL) { - mcast_buff = &((cmd->non_tx_cmd)->ntcb.multicast); - cb_hdr = &((cmd->non_tx_cmd)->ntcb.multicast.mc_cbhdr); - } else { - return; - } - - /* initialize the multi cast command */ - cb_hdr->cb_cmd = __constant_cpu_to_le16(CB_MULTICAST); - - /* now fill in the rest of the multicast command */ - *(u16 *) (&(mcast_buff->mc_count)) = cpu_to_le16(dev->mc_count * 6); - for (i = 0, mc_list = dev->mc_list; - (i < dev->mc_count) && (i < MAX_MULTICAST_ADDRS); - i++, mc_list = mc_list->next) { - /* copy into the command */ - memcpy(&(mcast_buff->mc_addr[i * ETH_ALEN]), - (u8 *) &(mc_list->dmi_addr), ETH_ALEN); - } - - if (!e100_exec_non_cu_cmd(bdp, cmd)) { - printk(KERN_WARNING "e100: %s: Multicast setup failed\n", - dev->name); - } -} - -/** - * e100_set_multi - set multicast status - * @dev: adapter's net_device struct - * - * This routine is called to add or remove multicast addresses, and/or to - * change the adapter's promiscuous state. - */ -static void -e100_set_multi(struct net_device *dev) -{ - struct e100_private *bdp = dev->priv; - unsigned char promisc_enbl; - unsigned char mulcast_enbl; - - promisc_enbl = ((dev->flags & IFF_PROMISC) == IFF_PROMISC); - mulcast_enbl = ((dev->flags & IFF_ALLMULTI) || - (dev->mc_count > MAX_MULTICAST_ADDRS)); - - e100_config_promisc(bdp, promisc_enbl); - e100_config_mulcast_enbl(bdp, mulcast_enbl); - - /* reconfigure the chip if something has changed in its config space */ - e100_config(bdp); - - if (promisc_enbl || mulcast_enbl) { - return; /* no need for Multicast Cmd */ - } - - /* get the multicast CB */ - e100_set_multi_exec(dev); -} - -static int -e100_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) -{ - - switch (cmd) { - - case SIOCETHTOOL: - return e100_do_ethtool_ioctl(dev, ifr); - break; - - case SIOCGMIIPHY: /* Get address of MII PHY in use. */ - case SIOCGMIIREG: /* Read MII PHY register. */ - case SIOCSMIIREG: /* Write to MII PHY register. */ - return e100_mii_ioctl(dev, ifr, cmd); - break; - - default: - return -EOPNOTSUPP; - } - return 0; - -} - -/** - * e100init - initialize the adapter - * @bdp: atapter's private data struct - * - * This routine is called when this driver is loaded. This is the initialization - * routine which allocates memory, configures the adapter and determines the - * system resources. - * - * Returns: - * true: if successful - * false: otherwise - */ -static unsigned char -e100_init(struct e100_private *bdp) -{ - u32 st_timeout = 0; - u32 st_result = 0; - e100_sw_init(bdp); - - if (!e100_selftest(bdp, &st_timeout, &st_result)) { - if (st_timeout) { - printk(KERN_ERR "e100: selftest timeout\n"); - } else { - printk(KERN_ERR "e100: selftest failed. Results: %x\n", - st_result); - } - return false; - } - else - printk(KERN_DEBUG "e100: selftest OK.\n"); - - /* read the MAC address from the eprom */ - e100_rd_eaddr(bdp); - if (!is_valid_ether_addr(bdp->device->dev_addr)) { - printk(KERN_ERR "e100: Invalid Ethernet address\n"); - return false; - } - /* read NIC's part number */ - e100_rd_pwa_no(bdp); - - if (!e100_hw_init(bdp)) - return false; - /* Interrupts are enabled after device reset */ - e100_disable_clear_intr(bdp); - - return true; -} - -/** - * e100_sw_init - initialize software structs - * @bdp: atapter's private data struct - * - * This routine initializes all software structures. Sets up the - * circular structures for the RFD's & TCB's. Allocates the per board - * structure for storing adapter information. The CSR is also memory - * mapped in this routine. - * - * Returns : - * true: if S/W was successfully initialized - * false: otherwise - */ -static unsigned char -e100_sw_init(struct e100_private *bdp) -{ - bdp->next_cu_cmd = START_WAIT; // init the next cu state - - /* - * Set the value for # of good xmits per underrun. the value assigned - * here is an intelligent suggested default. Nothing magical about it. - */ - bdp->tx_per_underrun = DEFAULT_TX_PER_UNDERRUN; - - /* get the default transmit threshold value */ - bdp->tx_thld = TX_THRSHLD; - - /* get the EPROM size */ - bdp->eeprom_size = e100_eeprom_size(bdp); - - /* Initialize our spinlocks */ - spin_lock_init(&(bdp->bd_lock)); - spin_lock_init(&(bdp->bd_non_tx_lock)); - spin_lock_init(&(bdp->config_lock)); - spin_lock_init(&(bdp->mdi_access_lock)); - /* Initialize configuration data */ - e100_config_init(bdp); - - return 1; -} - -static void -e100_tco_workaround(struct e100_private *bdp) -{ - int i; - - /* Do software reset */ - e100_sw_reset(bdp, PORT_SOFTWARE_RESET); - - /* Do a dummy LOAD CU BASE command. */ - /* This gets us out of pre-driver to post-driver. */ - e100_exec_cmplx(bdp, 0, SCB_CUC_LOAD_BASE); - - /* Wait 20 msec for reset to take effect */ - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(HZ / 50 + 1); - - /* disable interrupts since they are enabled */ - /* after device reset */ - e100_disable_clear_intr(bdp); - - /* Wait for command to be cleared up to 1 sec */ - for (i=0; i<100; i++) { - if (!readb(&bdp->scb->scb_cmd_low)) - break; - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(HZ / 100 + 1); - } - - /* Wait for TCO request bit in PMDR register to be clear */ - for (i=0; i<50; i++) { - if (!(readb(&bdp->scb->scb_ext.d101m_scb.scb_pmdr) & BIT_1)) - break; - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(HZ / 100 + 1); - } -} - -/** - * e100_hw_init - initialized tthe hardware - * @bdp: atapter's private data struct - * - * This routine performs a reset on the adapter, and configures the adapter. - * This includes configuring the 82557 LAN controller, validating and setting - * the node address, detecting and configuring the Phy chip on the adapter, - * and initializing all of the on chip counters. - * - * Returns: - * true - If the adapter was initialized - * false - If the adapter failed initialization - */ -unsigned char -e100_hw_init(struct e100_private *bdp) -{ - if (!e100_phy_init(bdp)) - goto err; - - e100_sw_reset(bdp, PORT_SELECTIVE_RESET); - - /* Only 82559 or above needs TCO workaround */ - if (bdp->rev_id >= D101MA_REV_ID) - e100_tco_workaround(bdp); - - /* Load the CU BASE (set to 0, because we use linear mode) */ - if (!e100_wait_exec_cmplx(bdp, 0, SCB_CUC_LOAD_BASE, 0)) - goto err; - - if (!e100_wait_exec_cmplx(bdp, 0, SCB_RUC_LOAD_BASE, 0)) - goto err; - - /* Load interrupt microcode */ - if (e100_load_microcode(bdp)) { - bdp->flags |= DF_UCODE_LOADED; - } - - if ((u8) bdp->rev_id < D101A4_REV_ID) - e100_config_init_82557(bdp); - - if (!e100_config(bdp)) - goto err; - - if (!e100_setup_iaaddr(bdp, bdp->device->dev_addr)) - goto err; - - /* Clear the internal counters */ - if (!e100_clr_cntrs(bdp)) - goto err; - - /* Change for 82558 enhancement */ - /* If 82558/9 and if the user has enabled flow control, set up the - * Flow Control Reg. in the CSR */ - if ((bdp->flags & IS_BACHELOR) - && (bdp->params.b_params & PRM_FC)) { - writeb(DFLT_FC_THLD, &bdp->scb->scb_ext.d101_scb.scb_fc_thld); - writeb(DFLT_FC_CMD, - &bdp->scb->scb_ext.d101_scb.scb_fc_xon_xoff); - } - - return true; -err: - printk(KERN_ERR "e100: hw init failed\n"); - return false; -} - -/** - * e100_setup_tcb_pool - setup TCB circular list - * @head: Pointer to head of the allocated TCBs - * @qlen: Number of elements in the queue - * @bdp: atapter's private data struct - * - * This routine arranges the contigiously allocated TCB's in a circular list. - * Also does the one time initialization of the TCBs. - */ -static void -e100_setup_tcb_pool(tcb_t *head, unsigned int qlen, struct e100_private *bdp) -{ - int ele_no; - tcb_t *pcurr_tcb; /* point to current tcb */ - u32 next_phys; /* the next phys addr */ - u16 txcommand = CB_S_BIT | CB_TX_SF_BIT; - - bdp->tx_count = 0; - if (bdp->flags & USE_IPCB) { - txcommand |= CB_IPCB_TRANSMIT | CB_CID_DEFAULT; - } else if (bdp->flags & IS_BACHELOR) { - txcommand |= CB_TRANSMIT | CB_CID_DEFAULT; - } else { - txcommand |= CB_TRANSMIT; - } - - for (ele_no = 0, next_phys = bdp->tcb_phys, pcurr_tcb = head; - ele_no < qlen; ele_no++, pcurr_tcb++) { - - /* set the phys addr for this TCB, next_phys has not incr. yet */ - pcurr_tcb->tcb_phys = next_phys; - next_phys += sizeof (tcb_t); - - /* set the link to next tcb */ - if (ele_no == (qlen - 1)) - pcurr_tcb->tcb_hdr.cb_lnk_ptr = - cpu_to_le32(bdp->tcb_phys); - else - pcurr_tcb->tcb_hdr.cb_lnk_ptr = cpu_to_le32(next_phys); - - pcurr_tcb->tcb_hdr.cb_status = 0; - pcurr_tcb->tcb_hdr.cb_cmd = cpu_to_le16(txcommand); - pcurr_tcb->tcb_cnt = 0; - pcurr_tcb->tcb_thrshld = bdp->tx_thld; - if (ele_no < 2) { - pcurr_tcb->tcb_hdr.cb_status = - cpu_to_le16(CB_STATUS_COMPLETE); - } - pcurr_tcb->tcb_tbd_num = 1; - - if (bdp->flags & IS_BACHELOR) { - pcurr_tcb->tcb_tbd_ptr = - __constant_cpu_to_le32(0xFFFFFFFF); - } else { - pcurr_tcb->tcb_tbd_ptr = - cpu_to_le32(pcurr_tcb->tcb_phys + 0x10); - } - - if (bdp->flags & IS_BACHELOR) { - pcurr_tcb->tcb_tbd_expand_ptr = - cpu_to_le32(pcurr_tcb->tcb_phys + 0x20); - } else { - pcurr_tcb->tcb_tbd_expand_ptr = - cpu_to_le32(pcurr_tcb->tcb_phys + 0x10); - } - pcurr_tcb->tcb_tbd_dflt_ptr = pcurr_tcb->tcb_tbd_ptr; - - if (bdp->flags & USE_IPCB) { - pcurr_tcb->tbd_ptr = &(pcurr_tcb->tcbu.tbd_array[1]); - pcurr_tcb->tcbu.ipcb.ip_activation_high = - IPCB_IP_ACTIVATION_DEFAULT; - pcurr_tcb->tcbu.ipcb.vlan = 0; - } else { - pcurr_tcb->tbd_ptr = &(pcurr_tcb->tcbu.tbd_array[0]); - } - - pcurr_tcb->tcb_skb = NULL; - } - - wmb(); -} - -/***************************************************************************/ -/***************************************************************************/ -/* Memory Management Routines */ -/***************************************************************************/ - -/** - * e100_alloc_space - allocate private driver data - * @bdp: atapter's private data struct - * - * This routine allocates memory for the driver. Memory allocated is for the - * selftest and statistics structures. - * - * Returns: - * 0: if the operation was successful - * %-ENOMEM: if memory allocation failed - */ -unsigned char -e100_alloc_space(struct e100_private *bdp) -{ - unsigned long off; - - /* allocate all the dma-able structures in one call: - * selftest results, adapter stats, and non-tx cb commands */ - if (!(bdp->dma_able = - pci_alloc_consistent(bdp->pdev, sizeof (bd_dma_able_t), - &(bdp->dma_able_phys)))) { - goto err; - } - - /* now assign the various pointers into the struct we've just allocated */ - off = offsetof(bd_dma_able_t, selftest); - - bdp->selftest = (self_test_t *) (bdp->dma_able + off); - bdp->selftest_phys = bdp->dma_able_phys + off; - - off = offsetof(bd_dma_able_t, stats_counters); - - bdp->stats_counters = (max_counters_t *) (bdp->dma_able + off); - bdp->stat_cnt_phys = bdp->dma_able_phys + off; - - return 0; - -err: - printk(KERN_ERR - "e100: Failed to allocate memory\n"); - return -ENOMEM; -} - -/** - * e100_alloc_tcb_pool - allocate TCB circular list - * @bdp: atapter's private data struct - * - * This routine allocates memory for the circular list of transmit descriptors. - * - * Returns: - * 0: if allocation has failed. - * 1: Otherwise. - */ -int -e100_alloc_tcb_pool(struct e100_private *bdp) -{ - int stcb = sizeof (tcb_t) * bdp->params.TxDescriptors; - - /* allocate space for the TCBs */ - if (!(bdp->tcb_pool.data = - pci_alloc_consistent(bdp->pdev, stcb, &bdp->tcb_phys))) - return 0; - - memset(bdp->tcb_pool.data, 0x00, stcb); - - return 1; -} - -void -e100_free_tcb_pool(struct e100_private *bdp) -{ - tcb_t *tcb; - int i; - /* Return tx skbs */ - for (i = 0; i < bdp->params.TxDescriptors; i++) { - tcb = bdp->tcb_pool.data; - tcb += bdp->tcb_pool.head; - e100_tx_skb_free(bdp, tcb); - if (NEXT_TCB_TOUSE(bdp->tcb_pool.head) == bdp->tcb_pool.tail) - break; - bdp->tcb_pool.head = NEXT_TCB_TOUSE(bdp->tcb_pool.head); - } - pci_free_consistent(bdp->pdev, - sizeof (tcb_t) * bdp->params.TxDescriptors, - bdp->tcb_pool.data, bdp->tcb_phys); - bdp->tcb_pool.head = 0; - bdp->tcb_pool.tail = 1; - bdp->tcb_phys = 0; -} - -static void -e100_dealloc_space(struct e100_private *bdp) -{ - if (bdp->dma_able) { - pci_free_consistent(bdp->pdev, sizeof (bd_dma_able_t), - bdp->dma_able, bdp->dma_able_phys); - } - - bdp->selftest_phys = 0; - bdp->stat_cnt_phys = 0; - bdp->dma_able_phys = 0; - bdp->dma_able = 0; -} - -static void -e100_free_rfd_pool(struct e100_private *bdp) -{ - struct rx_list_elem *rx_struct; - - while (!list_empty(&(bdp->active_rx_list))) { - - rx_struct = list_entry(bdp->active_rx_list.next, - struct rx_list_elem, list_elem); - list_del(&(rx_struct->list_elem)); - pci_unmap_single(bdp->pdev, rx_struct->dma_addr, - sizeof (rfd_t), PCI_DMA_TODEVICE); - dev_kfree_skb(rx_struct->skb); - kfree(rx_struct); - } - - while (!list_empty(&(bdp->rx_struct_pool))) { - rx_struct = list_entry(bdp->rx_struct_pool.next, - struct rx_list_elem, list_elem); - list_del(&(rx_struct->list_elem)); - kfree(rx_struct); - } -} - -/** - * e100_alloc_rfd_pool - allocate RFDs - * @bdp: atapter's private data struct - * - * Allocates initial pool of skb which holds both rfd and data, - * and return a pointer to the head of the list - */ -static int -e100_alloc_rfd_pool(struct e100_private *bdp) -{ - struct rx_list_elem *rx_struct; - int i; - - INIT_LIST_HEAD(&(bdp->active_rx_list)); - INIT_LIST_HEAD(&(bdp->rx_struct_pool)); - bdp->skb_req = bdp->params.RxDescriptors; - for (i = 0; i < bdp->skb_req; i++) { - rx_struct = kmalloc(sizeof (struct rx_list_elem), GFP_ATOMIC); - list_add(&(rx_struct->list_elem), &(bdp->rx_struct_pool)); - } - e100_alloc_skbs(bdp); - return !list_empty(&(bdp->active_rx_list)); - -} - -void -e100_clear_pools(struct e100_private *bdp) -{ - bdp->last_tcb = NULL; - e100_free_rfd_pool(bdp); - e100_free_tcb_pool(bdp); -} - -/*****************************************************************************/ -/*****************************************************************************/ -/* Run Time Functions */ -/*****************************************************************************/ - -/** - * e100_watchdog - * @dev: adapter's net_device struct - * - * This routine runs every 2 seconds and updates our statitics and link state, - * and refreshs txthld value. - */ -void -e100_watchdog(struct net_device *dev) -{ - struct e100_private *bdp = dev->priv; - -#ifdef E100_CU_DEBUG - if (e100_cu_unknown_state(bdp)) { - printk(KERN_ERR "e100: %s: CU unknown state in e100_watchdog\n", - dev->name); - } -#endif - if (!netif_running(dev)) { - return; - } - - /* check if link state has changed */ - if (e100_phy_check(bdp)) { - if (netif_carrier_ok(dev)) { - printk(KERN_ERR - "e100: %s NIC Link is Up %d Mbps %s duplex\n", - bdp->device->name, bdp->cur_line_speed, - (bdp->cur_dplx_mode == HALF_DUPLEX) ? - "Half" : "Full"); - - e100_config_fc(bdp); - e100_config(bdp); - - } else { - printk(KERN_ERR "e100: %s NIC Link is Down\n", - bdp->device->name); - } - } - - // toggle the tx queue according to link status - // this also resolves a race condition between tx & non-cu cmd flows - if (netif_carrier_ok(dev)) { - if (netif_running(dev)) - netif_wake_queue(dev); - } else { - if (netif_running(dev)) - netif_stop_queue(dev); - /* When changing to non-autoneg, device may lose */ - /* link with some switches. e100 will try to */ - /* revover link by sending command to PHY layer */ - if (bdp->params.e100_speed_duplex != E100_AUTONEG) - e100_force_speed_duplex_to_phy(bdp); - } - - rmb(); - - if (e100_update_stats(bdp)) { - - /* Check if a change in the IFS parameter is needed, - and configure the device accordingly */ - if (bdp->params.b_params & PRM_IFS) - e100_manage_adaptive_ifs(bdp); - - /* Now adjust our dynamic tx threshold value */ - e100_refresh_txthld(bdp); - - /* Now if we are on a 557 and we havn't received any frames then we - * should issue a multicast command to reset the RU */ - if (bdp->rev_id < D101A4_REV_ID) { - if (!(bdp->stats_counters->basic_stats.rcv_gd_frames)) { - e100_set_multi(dev); - } - } - } - /* Issue command to dump statistics from device. */ - /* Check for command completion on next watchdog timer. */ - e100_dump_stats_cntrs(bdp); - - wmb(); - - /* relaunch watchdog timer in 2 sec */ - mod_timer(&(bdp->watchdog_timer), jiffies + (2 * HZ)); - - if (list_empty(&bdp->active_rx_list)) - e100_trigger_SWI(bdp); -} - -/** - * e100_manage_adaptive_ifs - * @bdp: atapter's private data struct - * - * This routine manages the adaptive Inter-Frame Spacing algorithm - * using a state machine. - */ -void -e100_manage_adaptive_ifs(struct e100_private *bdp) -{ - static u16 state_table[9][4] = { // rows are states - {2, 0, 0, 0}, // state0 // column0: next state if increasing - {2, 0, 5, 30}, // state1 // column1: next state if decreasing - {5, 1, 5, 30}, // state2 // column2: IFS value for 100 mbit - {5, 3, 0, 0}, // state3 // column3: IFS value for 10 mbit - {5, 3, 10, 60}, // state4 - {8, 4, 10, 60}, // state5 - {8, 6, 0, 0}, // state6 - {8, 6, 20, 60}, // state7 - {8, 7, 20, 60} // state8 - }; - - u32 transmits = - le32_to_cpu(bdp->stats_counters->basic_stats.xmt_gd_frames); - u32 collisions = - le32_to_cpu(bdp->stats_counters->basic_stats.xmt_ttl_coll); - u32 state = bdp->ifs_state; - u32 old_value = bdp->ifs_value; - int next_col; - u32 min_transmits; - - if (bdp->cur_dplx_mode == FULL_DUPLEX) { - bdp->ifs_state = 0; - bdp->ifs_value = 0; - - } else { /* Half Duplex */ - /* Set speed specific parameters */ - if (bdp->cur_line_speed == 100) { - next_col = 2; - min_transmits = MIN_NUMBER_OF_TRANSMITS_100; - - } else { /* 10 Mbps */ - next_col = 3; - min_transmits = MIN_NUMBER_OF_TRANSMITS_10; - } - - if ((transmits / 32 < collisions) - && (transmits > min_transmits)) { - state = state_table[state][0]; /* increment */ - - } else if (transmits < min_transmits) { - state = state_table[state][1]; /* decrement */ - } - - bdp->ifs_value = state_table[state][next_col]; - bdp->ifs_state = state; - } - - /* If the IFS value has changed, configure the device */ - if (bdp->ifs_value != old_value) { - e100_config_ifs(bdp); - e100_config(bdp); - } -} - -/** - * e100intr - interrupt handler - * @irq: the IRQ number - * @dev_inst: the net_device struct - * @regs: registers (unused) - * - * This routine is the ISR for the e100 board. It services - * the RX & TX queues & starts the RU if it has stopped due - * to no resources. - */ -irqreturn_t -e100intr(int irq, void *dev_inst, struct pt_regs *regs) -{ - struct net_device *dev; - struct e100_private *bdp; - u16 intr_status; - - dev = dev_inst; - bdp = dev->priv; - - intr_status = readw(&bdp->scb->scb_status); - /* If not my interrupt, just return */ - if (!(intr_status & SCB_STATUS_ACK_MASK) || (intr_status == 0xffff)) { - return IRQ_NONE; - } - - /* disable and ack intr */ - e100_disable_clear_intr(bdp); - - /* the device is closed, don't continue or else bad things may happen. */ - if (!netif_running(dev)) { - e100_set_intr_mask(bdp); - return IRQ_NONE; - } - - /* SWI intr (triggered by watchdog) is signal to allocate new skb buffers */ - if (intr_status & SCB_STATUS_ACK_SWI) { - e100_alloc_skbs(bdp); - } - - /* do recv work if any */ - if (intr_status & - (SCB_STATUS_ACK_FR | SCB_STATUS_ACK_RNR | SCB_STATUS_ACK_SWI)) - bdp->drv_stats.rx_intr_pkts += e100_rx_srv(bdp); - - /* clean up after tx'ed packets */ - if (intr_status & (SCB_STATUS_ACK_CNA | SCB_STATUS_ACK_CX)) - e100_tx_srv(bdp); - - e100_set_intr_mask(bdp); - return IRQ_HANDLED; -} - -/** - * e100_tx_skb_free - free TX skbs resources - * @bdp: atapter's private data struct - * @tcb: associated tcb of the freed skb - * - * This routine frees resources of TX skbs. - */ -static inline void -e100_tx_skb_free(struct e100_private *bdp, tcb_t *tcb) -{ - if (tcb->tcb_skb) { - int i; - tbd_t *tbd_arr = tcb->tbd_ptr; - int frags = skb_shinfo(tcb->tcb_skb)->nr_frags; - - for (i = 0; i <= frags; i++, tbd_arr++) { - pci_unmap_single(bdp->pdev, - le32_to_cpu(tbd_arr->tbd_buf_addr), - le16_to_cpu(tbd_arr->tbd_buf_cnt), - PCI_DMA_TODEVICE); - } - dev_kfree_skb_irq(tcb->tcb_skb); - tcb->tcb_skb = NULL; - } -} - -/** - * e100_tx_srv - service TX queues - * @bdp: atapter's private data struct - * - * This routine services the TX queues. It reclaims the TCB's & TBD's & other - * resources used during the transmit of this buffer. It is called from the ISR. - * We don't need a tx_lock since we always access buffers which were already - * prepared. - */ -void -e100_tx_srv(struct e100_private *bdp) -{ - tcb_t *tcb; - int i; - - /* go over at most TxDescriptors buffers */ - for (i = 0; i < bdp->params.TxDescriptors; i++) { - tcb = bdp->tcb_pool.data; - tcb += bdp->tcb_pool.head; - - rmb(); - - /* if the buffer at 'head' is not complete, break */ - if (!(tcb->tcb_hdr.cb_status & - __constant_cpu_to_le16(CB_STATUS_COMPLETE))) - break; - - /* service next buffer, clear the out of resource condition */ - e100_tx_skb_free(bdp, tcb); - - if (netif_running(bdp->device)) - netif_wake_queue(bdp->device); - - /* if we've caught up with 'tail', break */ - if (NEXT_TCB_TOUSE(bdp->tcb_pool.head) == bdp->tcb_pool.tail) { - break; - } - - bdp->tcb_pool.head = NEXT_TCB_TOUSE(bdp->tcb_pool.head); - } -} - -/** - * e100_rx_srv - service RX queue - * @bdp: atapter's private data struct - * @max_number_of_rfds: max number of RFDs to process - * @rx_congestion: flag pointer, to inform the calling function of congestion. - * - * This routine processes the RX interrupt & services the RX queues. - * For each successful RFD, it allocates a new msg block, links that - * into the RFD list, and sends the old msg upstream. - * The new RFD is then put at the end of the free list of RFD's. - * It returns the number of serviced RFDs. - */ -u32 -e100_rx_srv(struct e100_private *bdp) -{ - rfd_t *rfd; /* new rfd, received rfd */ - int i; - u16 rfd_status; - struct sk_buff *skb; - struct net_device *dev; - unsigned int data_sz; - struct rx_list_elem *rx_struct; - u32 rfd_cnt = 0; - - dev = bdp->device; - - /* current design of rx is as following: - * 1. socket buffer (skb) used to pass network packet to upper layer - * 2. all HW host memory structures (like RFDs, RBDs and data buffers) - * are placed in a skb's data room - * 3. when rx process is complete, we change skb internal pointers to exclude - * from data area all unrelated things (RFD, RDB) and to leave - * just rx'ed packet netto - * 4. for each skb passed to upper layer, new one is allocated instead. - * 5. if no skb left, in 2 sec another atempt to allocate skbs will be made - * (watchdog trigger SWI intr and isr should allocate new skbs) - */ - for (i = 0; i < bdp->params.RxDescriptors; i++) { - if (list_empty(&(bdp->active_rx_list))) { - break; - } - - rx_struct = list_entry(bdp->active_rx_list.next, - struct rx_list_elem, list_elem); - skb = rx_struct->skb; - - rfd = RFD_POINTER(skb, bdp); /* locate RFD within skb */ - - // sync only the RFD header - pci_dma_sync_single(bdp->pdev, rx_struct->dma_addr, - bdp->rfd_size, PCI_DMA_FROMDEVICE); - rfd_status = le16_to_cpu(rfd->rfd_header.cb_status); /* get RFD's status */ - if (!(rfd_status & RFD_STATUS_COMPLETE)) /* does not contains data yet - exit */ - break; - - /* to allow manipulation with current skb we need to unlink it */ - list_del(&(rx_struct->list_elem)); - - /* do not free & unmap badly received packet. - * move it to the end of skb list for reuse */ - if (!(rfd_status & RFD_STATUS_OK)) { - e100_add_skb_to_end(bdp, rx_struct); - continue; - } - - data_sz = min_t(u16, (le16_to_cpu(rfd->rfd_act_cnt) & 0x3fff), - (sizeof (rfd_t) - bdp->rfd_size)); - - /* now sync all the data */ - pci_dma_sync_single(bdp->pdev, rx_struct->dma_addr, - (data_sz + bdp->rfd_size), - PCI_DMA_FROMDEVICE); - - pci_unmap_single(bdp->pdev, rx_struct->dma_addr, - sizeof (rfd_t), PCI_DMA_FROMDEVICE); - - list_add(&(rx_struct->list_elem), &(bdp->rx_struct_pool)); - - /* end of dma access to rfd */ - bdp->skb_req++; /* incr number of requested skbs */ - e100_alloc_skbs(bdp); /* and get them */ - - /* set packet size, excluding checksum (2 last bytes) if it is present */ - if ((bdp->flags & DF_CSUM_OFFLOAD) - && (bdp->rev_id < D102_REV_ID)) - skb_put(skb, (int) data_sz - 2); - else - skb_put(skb, (int) data_sz); - - /* set the protocol */ - skb->protocol = eth_type_trans(skb, dev); - - /* set the checksum info */ - if (bdp->flags & DF_CSUM_OFFLOAD) { - if (bdp->rev_id >= D102_REV_ID) { - skb->ip_summed = e100_D102_check_checksum(rfd); - } else { - skb->ip_summed = e100_D101M_checksum(bdp, skb); - } - } else { - skb->ip_summed = CHECKSUM_NONE; - } - - bdp->drv_stats.net_stats.rx_bytes += skb->len; - - if(bdp->vlgrp && (rfd_status & CB_STATUS_VLAN)) { - vlan_hwaccel_rx(skb, bdp->vlgrp, be16_to_cpu(rfd->vlanid)); - } else { - netif_rx(skb); - } - dev->last_rx = jiffies; - - rfd_cnt++; - } /* end of rfd loop */ - - /* restart the RU if it has stopped */ - if ((readw(&bdp->scb->scb_status) & SCB_RUS_MASK) != SCB_RUS_READY) { - e100_start_ru(bdp); - } - - return rfd_cnt; -} - -void -e100_refresh_txthld(struct e100_private *bdp) -{ - basic_cntr_t *pstat = &(bdp->stats_counters->basic_stats); - - /* as long as tx_per_underrun is not 0, we can go about dynamically * - * adjusting the xmit threshold. we stop doing that & resort to defaults - * * once the adjustments become meaningless. the value is adjusted by * - * dumping the error counters & checking the # of xmit underrun errors * - * we've had. */ - if (bdp->tx_per_underrun) { - /* We are going to last values dumped from the dump statistics - * command */ - if (le32_to_cpu(pstat->xmt_gd_frames)) { - if (le32_to_cpu(pstat->xmt_uruns)) { - /* - * if we have had more than one underrun per "DEFAULT # - * OF XMITS ALLOWED PER UNDERRUN" good xmits, raise the - * THRESHOLD. - */ - if ((le32_to_cpu(pstat->xmt_gd_frames) / - le32_to_cpu(pstat->xmt_uruns)) < - bdp->tx_per_underrun) { - bdp->tx_thld += 3; - } - } - - /* - * if we've had less than one underrun per the DEFAULT number of - * of good xmits allowed, lower the THOLD but not less than 0 - */ - if (le32_to_cpu(pstat->xmt_gd_frames) > - bdp->tx_per_underrun) { - bdp->tx_thld--; - - if (bdp->tx_thld < 6) - bdp->tx_thld = 6; - - } - } - - /* end good xmits */ - /* - * * if our adjustments are becoming unresonable, stop adjusting & - * resort * to defaults & pray. A THOLD value > 190 means that the - * adapter will * wait for 190*8=1520 bytes in TX FIFO before it - * starts xmit. Since * MTU is 1514, it doesn't make any sense for - * further increase. */ - if (bdp->tx_thld >= 190) { - bdp->tx_per_underrun = 0; - bdp->tx_thld = 189; - } - } /* end underrun check */ -} - -/** - * e100_prepare_xmit_buff - prepare a buffer for transmission - * @bdp: atapter's private data struct - * @skb: skb to send - * - * This routine prepare a buffer for transmission. It checks - * the message length for the appropiate size. It picks up a - * free tcb from the TCB pool and sets up the corresponding - * TBD's. If the number of fragments are more than the number - * of TBD/TCB it copies all the fragments in a coalesce buffer. - * It returns a pointer to the prepared TCB. - */ -static inline tcb_t * -e100_prepare_xmit_buff(struct e100_private *bdp, struct sk_buff *skb) -{ - tcb_t *tcb, *prev_tcb; - - tcb = bdp->tcb_pool.data; - tcb += TCB_TO_USE(bdp->tcb_pool); - - if (bdp->flags & USE_IPCB) { - tcb->tcbu.ipcb.ip_activation_high = IPCB_IP_ACTIVATION_DEFAULT; - tcb->tcbu.ipcb.ip_schedule &= ~IPCB_TCP_PACKET; - tcb->tcbu.ipcb.ip_schedule &= ~IPCB_TCPUDP_CHECKSUM_ENABLE; - } - - if(bdp->vlgrp && vlan_tx_tag_present(skb)) { - (tcb->tcbu).ipcb.ip_activation_high |= IPCB_INSERTVLAN_ENABLE; - (tcb->tcbu).ipcb.vlan = cpu_to_be16(vlan_tx_tag_get(skb)); - } - - tcb->tcb_hdr.cb_status = 0; - tcb->tcb_thrshld = bdp->tx_thld; - tcb->tcb_hdr.cb_cmd |= __constant_cpu_to_le16(CB_S_BIT); - - /* Set I (Interrupt) bit on every (TX_FRAME_CNT)th packet */ - if (!(++bdp->tx_count % TX_FRAME_CNT)) - tcb->tcb_hdr.cb_cmd |= __constant_cpu_to_le16(CB_I_BIT); - else - /* Clear I bit on other packets */ - tcb->tcb_hdr.cb_cmd &= ~__constant_cpu_to_le16(CB_I_BIT); - - tcb->tcb_skb = skb; - - if (skb->ip_summed == CHECKSUM_HW) { - const struct iphdr *ip = skb->nh.iph; - - if ((ip->protocol == IPPROTO_TCP) || - (ip->protocol == IPPROTO_UDP)) { - - tcb->tcbu.ipcb.ip_activation_high |= - IPCB_HARDWAREPARSING_ENABLE; - tcb->tcbu.ipcb.ip_schedule |= - IPCB_TCPUDP_CHECKSUM_ENABLE; - - if (ip->protocol == IPPROTO_TCP) - tcb->tcbu.ipcb.ip_schedule |= IPCB_TCP_PACKET; - } - } - - if (!skb_shinfo(skb)->nr_frags) { - (tcb->tbd_ptr)->tbd_buf_addr = - cpu_to_le32(pci_map_single(bdp->pdev, skb->data, - skb->len, PCI_DMA_TODEVICE)); - (tcb->tbd_ptr)->tbd_buf_cnt = cpu_to_le16(skb->len); - tcb->tcb_tbd_num = 1; - tcb->tcb_tbd_ptr = tcb->tcb_tbd_dflt_ptr; - } else { - int i; - void *addr; - tbd_t *tbd_arr_ptr = &(tcb->tbd_ptr[1]); - skb_frag_t *frag = &skb_shinfo(skb)->frags[0]; - - (tcb->tbd_ptr)->tbd_buf_addr = - cpu_to_le32(pci_map_single(bdp->pdev, skb->data, - skb_headlen(skb), - PCI_DMA_TODEVICE)); - (tcb->tbd_ptr)->tbd_buf_cnt = - cpu_to_le16(skb_headlen(skb)); - - for (i = 0; i < skb_shinfo(skb)->nr_frags; - i++, tbd_arr_ptr++, frag++) { - - addr = ((void *) page_address(frag->page) + - frag->page_offset); - - tbd_arr_ptr->tbd_buf_addr = - cpu_to_le32(pci_map_single(bdp->pdev, - addr, frag->size, - PCI_DMA_TODEVICE)); - tbd_arr_ptr->tbd_buf_cnt = cpu_to_le16(frag->size); - } - tcb->tcb_tbd_num = skb_shinfo(skb)->nr_frags + 1; - tcb->tcb_tbd_ptr = tcb->tcb_tbd_expand_ptr; - } - - /* clear the S-BIT on the previous tcb */ - prev_tcb = bdp->tcb_pool.data; - prev_tcb += PREV_TCB_USED(bdp->tcb_pool); - prev_tcb->tcb_hdr.cb_cmd &= __constant_cpu_to_le16((u16) ~CB_S_BIT); - - bdp->tcb_pool.tail = NEXT_TCB_TOUSE(bdp->tcb_pool.tail); - - wmb(); - - e100_start_cu(bdp, tcb); - - return tcb; -} - -/* Changed for 82558 enhancement */ -/** - * e100_start_cu - start the adapter's CU - * @bdp: atapter's private data struct - * @tcb: TCB to be transmitted - * - * This routine issues a CU Start or CU Resume command to the 82558/9. - * This routine was added because the prepare_ext_xmit_buff takes advantage - * of the 82558/9's Dynamic TBD chaining feature and has to start the CU as - * soon as the first TBD is ready. - * - * e100_start_cu must be called while holding the tx_lock ! - */ -u8 -e100_start_cu(struct e100_private *bdp, tcb_t *tcb) -{ - unsigned long lock_flag; - u8 ret = true; - - spin_lock_irqsave(&(bdp->bd_lock), lock_flag); - switch (bdp->next_cu_cmd) { - case RESUME_NO_WAIT: - /*last cu command was a CU_RESMUE if this is a 558 or newer we don't need to - * wait for command word to clear, we reach here only if we are bachlor - */ - e100_exec_cmd(bdp, SCB_CUC_RESUME); - break; - - case RESUME_WAIT: - if ((bdp->flags & IS_ICH) && - (bdp->cur_line_speed == 10) && - (bdp->cur_dplx_mode == HALF_DUPLEX)) { - e100_wait_exec_simple(bdp, SCB_CUC_NOOP); - udelay(1); - } - if ((e100_wait_exec_simple(bdp, SCB_CUC_RESUME)) && - (bdp->flags & IS_BACHELOR) && (!(bdp->flags & IS_ICH))) { - bdp->next_cu_cmd = RESUME_NO_WAIT; - } - break; - - case START_WAIT: - // The last command was a non_tx CU command - if (!e100_wait_cus_idle(bdp)) - printk(KERN_DEBUG - "e100: %s: cu_start: timeout waiting for cu\n", - bdp->device->name); - if (!e100_wait_exec_cmplx(bdp, (u32) (tcb->tcb_phys), - SCB_CUC_START, CB_TRANSMIT)) { - printk(KERN_DEBUG - "e100: %s: cu_start: timeout waiting for scb\n", - bdp->device->name); - e100_exec_cmplx(bdp, (u32) (tcb->tcb_phys), - SCB_CUC_START); - ret = false; - } - - bdp->next_cu_cmd = RESUME_WAIT; - - break; - } - - /* save the last tcb */ - bdp->last_tcb = tcb; - - spin_unlock_irqrestore(&(bdp->bd_lock), lock_flag); - return ret; -} - -/* ====================================================================== */ -/* hw */ -/* ====================================================================== */ - -/** - * e100_selftest - perform H/W self test - * @bdp: atapter's private data struct - * @st_timeout: address to return timeout value, if fails - * @st_result: address to return selftest result, if fails - * - * This routine will issue PORT Self-test command to test the e100. - * The self-test will fail if the adapter's master-enable bit is not - * set in the PCI Command Register, or if the adapter is not seated - * in a PCI master-enabled slot. we also disable interrupts when the - * command is completed. - * - * Returns: - * true: if adapter passes self_test - * false: otherwise - */ -unsigned char -e100_selftest(struct e100_private *bdp, u32 *st_timeout, u32 *st_result) -{ - u32 selftest_cmd; - - /* initialize the nic state before running test */ - e100_sw_reset(bdp, PORT_SOFTWARE_RESET); - /* Setup the address of the self_test area */ - selftest_cmd = bdp->selftest_phys; - - /* Setup SELF TEST Command Code in D3 - D0 */ - selftest_cmd |= PORT_SELFTEST; - - /* Initialize the self-test signature and results DWORDS */ - bdp->selftest->st_sign = 0; - bdp->selftest->st_result = 0xffffffff; - - /* Do the port command */ - writel(selftest_cmd, &bdp->scb->scb_port); - readw(&(bdp->scb->scb_status)); /* flushes last write, read-safe */ - - /* Wait at least 10 milliseconds for the self-test to complete */ - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(HZ / 100 + 1); - - /* disable interrupts since they are enabled */ - /* after device reset during selftest */ - e100_disable_clear_intr(bdp); - - /* if The First Self Test DWORD Still Zero, We've timed out. If the - * second DWORD is not zero then we have an error. */ - if ((bdp->selftest->st_sign == 0) || (bdp->selftest->st_result != 0)) { - - if (st_timeout) - *st_timeout = !(le32_to_cpu(bdp->selftest->st_sign)); - - if (st_result) - *st_result = le32_to_cpu(bdp->selftest->st_result); - - return false; - } - - return true; -} - -/** - * e100_setup_iaaddr - issue IA setup sommand - * @bdp: atapter's private data struct - * @eaddr: new ethernet address - * - * This routine will issue the IA setup command. This command - * will notify the 82557 (e100) of what its individual (node) - * address is. This command will be executed in polled mode. - * - * Returns: - * true: if the IA setup command was successfully issued and completed - * false: otherwise - */ -unsigned char -e100_setup_iaaddr(struct e100_private *bdp, u8 *eaddr) -{ - unsigned int i; - cb_header_t *ntcb_hdr; - unsigned char res; - nxmit_cb_entry_t *cmd; - - if ((cmd = e100_alloc_non_tx_cmd(bdp)) == NULL) { - res = false; - goto exit; - } - - ntcb_hdr = (cb_header_t *) cmd->non_tx_cmd; - ntcb_hdr->cb_cmd = __constant_cpu_to_le16(CB_IA_ADDRESS); - - for (i = 0; i < ETH_ALEN; i++) { - (cmd->non_tx_cmd)->ntcb.setup.ia_addr[i] = eaddr[i]; - } - - res = e100_exec_non_cu_cmd(bdp, cmd); - if (!res) - printk(KERN_WARNING "e100: %s: IA setup failed\n", - bdp->device->name); - -exit: - return res; -} - -/** - * e100_start_ru - start the RU if needed - * @bdp: atapter's private data struct - * - * This routine checks the status of the 82557's receive unit(RU), - * and starts the RU if it was not already active. However, - * before restarting the RU, the driver gives the RU the buffers - * it freed up during the servicing of the ISR. If there are - * no free buffers to give to the RU, (i.e. we have reached a - * no resource condition) the RU will not be started till the - * next ISR. - */ -void -e100_start_ru(struct e100_private *bdp) -{ - struct rx_list_elem *rx_struct = NULL; - int buffer_found = 0; - struct list_head *entry_ptr; - - list_for_each(entry_ptr, &(bdp->active_rx_list)) { - rx_struct = - list_entry(entry_ptr, struct rx_list_elem, list_elem); - pci_dma_sync_single(bdp->pdev, rx_struct->dma_addr, - bdp->rfd_size, PCI_DMA_FROMDEVICE); - if (!((SKB_RFD_STATUS(rx_struct->skb, bdp) & - __constant_cpu_to_le16(RFD_STATUS_COMPLETE)))) { - buffer_found = 1; - break; - } - } - - /* No available buffers */ - if (!buffer_found) { - return; - } - - spin_lock(&bdp->bd_lock); - - if (!e100_wait_exec_cmplx(bdp, rx_struct->dma_addr, SCB_RUC_START, 0)) { - printk(KERN_DEBUG - "e100: %s: start_ru: wait_scb failed\n", - bdp->device->name); - e100_exec_cmplx(bdp, rx_struct->dma_addr, SCB_RUC_START); - } - if (bdp->next_cu_cmd == RESUME_NO_WAIT) { - bdp->next_cu_cmd = RESUME_WAIT; - } - spin_unlock(&bdp->bd_lock); -} - -/** - * e100_cmd_complete_location - * @bdp: atapter's private data struct - * - * This routine returns a pointer to the location of the command-complete - * DWord in the dump statistical counters area, according to the statistical - * counters mode (557 - basic, 558 - extended, or 559 - TCO mode). - * See e100_config_init() for the setting of the statistical counters mode. - */ -static u32 * -e100_cmd_complete_location(struct e100_private *bdp) -{ - u32 *cmd_complete; - max_counters_t *stats = bdp->stats_counters; - - switch (bdp->stat_mode) { - case E100_EXTENDED_STATS: - cmd_complete = - (u32 *) &(((err_cntr_558_t *) (stats))->cmd_complete); - break; - - case E100_TCO_STATS: - cmd_complete = - (u32 *) &(((err_cntr_559_t *) (stats))->cmd_complete); - break; - - case E100_BASIC_STATS: - default: - cmd_complete = - (u32 *) &(((err_cntr_557_t *) (stats))->cmd_complete); - break; - } - - return cmd_complete; -} - -/** - * e100_clr_cntrs - clear statistics counters - * @bdp: atapter's private data struct - * - * This routine will clear the adapter error statistic counters. - * - * Returns: - * true: if successfully cleared stat counters - * false: otherwise - */ -static unsigned char -e100_clr_cntrs(struct e100_private *bdp) -{ - volatile u32 *pcmd_complete; - - /* clear the dump counter complete word */ - pcmd_complete = e100_cmd_complete_location(bdp); - *pcmd_complete = 0; - wmb(); - - if (!e100_wait_exec_cmplx(bdp, bdp->stat_cnt_phys, SCB_CUC_DUMP_ADDR, 0)) - return false; - - /* wait 10 microseconds for the command to complete */ - udelay(10); - - if (!e100_wait_exec_simple(bdp, SCB_CUC_DUMP_RST_STAT)) - return false; - - if (bdp->next_cu_cmd == RESUME_NO_WAIT) { - bdp->next_cu_cmd = RESUME_WAIT; - } - - return true; -} - -static unsigned char -e100_update_stats(struct e100_private *bdp) -{ - u32 *pcmd_complete; - basic_cntr_t *pstat = &(bdp->stats_counters->basic_stats); - - // check if last dump command completed - pcmd_complete = e100_cmd_complete_location(bdp); - if (*pcmd_complete != le32_to_cpu(DUMP_RST_STAT_COMPLETED) && - *pcmd_complete != le32_to_cpu(DUMP_STAT_COMPLETED)) { - *pcmd_complete = 0; - return false; - } - - /* increment the statistics */ - bdp->drv_stats.net_stats.rx_packets += - le32_to_cpu(pstat->rcv_gd_frames); - bdp->drv_stats.net_stats.tx_packets += - le32_to_cpu(pstat->xmt_gd_frames); - bdp->drv_stats.net_stats.rx_dropped += le32_to_cpu(pstat->rcv_rsrc_err); - bdp->drv_stats.net_stats.collisions += le32_to_cpu(pstat->xmt_ttl_coll); - bdp->drv_stats.net_stats.rx_length_errors += - le32_to_cpu(pstat->rcv_shrt_frames); - bdp->drv_stats.net_stats.rx_over_errors += - le32_to_cpu(pstat->rcv_rsrc_err); - bdp->drv_stats.net_stats.rx_crc_errors += - le32_to_cpu(pstat->rcv_crc_errs); - bdp->drv_stats.net_stats.rx_frame_errors += - le32_to_cpu(pstat->rcv_algn_errs); - bdp->drv_stats.net_stats.rx_fifo_errors += - le32_to_cpu(pstat->rcv_oruns); - bdp->drv_stats.net_stats.tx_aborted_errors += - le32_to_cpu(pstat->xmt_max_coll); - bdp->drv_stats.net_stats.tx_carrier_errors += - le32_to_cpu(pstat->xmt_lost_crs); - bdp->drv_stats.net_stats.tx_fifo_errors += - le32_to_cpu(pstat->xmt_uruns); - - bdp->drv_stats.tx_late_col += le32_to_cpu(pstat->xmt_late_coll); - bdp->drv_stats.tx_ok_defrd += le32_to_cpu(pstat->xmt_deferred); - bdp->drv_stats.tx_one_retry += le32_to_cpu(pstat->xmt_sngl_coll); - bdp->drv_stats.tx_mt_one_retry += le32_to_cpu(pstat->xmt_mlt_coll); - bdp->drv_stats.rcv_cdt_frames += le32_to_cpu(pstat->rcv_err_coll); - - if (bdp->stat_mode != E100_BASIC_STATS) { - ext_cntr_t *pex_stat = &bdp->stats_counters->extended_stats; - - bdp->drv_stats.xmt_fc_pkts += - le32_to_cpu(pex_stat->xmt_fc_frames); - bdp->drv_stats.rcv_fc_pkts += - le32_to_cpu(pex_stat->rcv_fc_frames); - bdp->drv_stats.rcv_fc_unsupported += - le32_to_cpu(pex_stat->rcv_fc_unsupported); - } - - if (bdp->stat_mode == E100_TCO_STATS) { - tco_cntr_t *ptco_stat = &bdp->stats_counters->tco_stats; - - bdp->drv_stats.xmt_tco_pkts += - le16_to_cpu(ptco_stat->xmt_tco_frames); - bdp->drv_stats.rcv_tco_pkts += - le16_to_cpu(ptco_stat->rcv_tco_frames); - } - - *pcmd_complete = 0; - return true; -} - -/** - * e100_dump_stat_cntrs - * @bdp: atapter's private data struct - * - * This routine will dump the board statistical counters without waiting - * for stat_dump to complete. Any access to this stats should verify the completion - * of the command - */ -void -e100_dump_stats_cntrs(struct e100_private *bdp) -{ - unsigned long lock_flag_bd; - - spin_lock_irqsave(&(bdp->bd_lock), lock_flag_bd); - - /* dump h/w stats counters */ - if (e100_wait_exec_simple(bdp, SCB_CUC_DUMP_RST_STAT)) { - if (bdp->next_cu_cmd == RESUME_NO_WAIT) { - bdp->next_cu_cmd = RESUME_WAIT; - } - } - - spin_unlock_irqrestore(&(bdp->bd_lock), lock_flag_bd); -} - -/** - * e100_exec_non_cu_cmd - * @bdp: atapter's private data struct - * @command: the non-cu command to execute - * - * This routine will submit a command block to be executed, - */ -unsigned char -e100_exec_non_cu_cmd(struct e100_private *bdp, nxmit_cb_entry_t *command) -{ - cb_header_t *ntcb_hdr; - unsigned long lock_flag; - unsigned long expiration_time; - unsigned char rc = true; - u8 sub_cmd; - - ntcb_hdr = (cb_header_t *) command->non_tx_cmd; /* get hdr of non tcb cmd */ - sub_cmd = cpu_to_le16(ntcb_hdr->cb_cmd); - - /* Set the Command Block to be the last command block */ - ntcb_hdr->cb_cmd |= __constant_cpu_to_le16(CB_EL_BIT); - ntcb_hdr->cb_status = 0; - ntcb_hdr->cb_lnk_ptr = 0; - - wmb(); - if (in_interrupt()) - return e100_delayed_exec_non_cu_cmd(bdp, command); - - if (netif_running(bdp->device) && netif_carrier_ok(bdp->device)) - return e100_delayed_exec_non_cu_cmd(bdp, command); - - spin_lock_bh(&(bdp->bd_non_tx_lock)); - - if (bdp->non_tx_command_state != E100_NON_TX_IDLE) { - goto delayed_exec; - } - - if (bdp->last_tcb) { - rmb(); - if ((bdp->last_tcb->tcb_hdr.cb_status & - __constant_cpu_to_le16(CB_STATUS_COMPLETE)) == 0) - goto delayed_exec; - } - - if ((readw(&bdp->scb->scb_status) & SCB_CUS_MASK) == SCB_CUS_ACTIVE) { - goto delayed_exec; - } - - spin_lock_irqsave(&bdp->bd_lock, lock_flag); - - if (!e100_wait_exec_cmplx(bdp, command->dma_addr, SCB_CUC_START, sub_cmd)) { - spin_unlock_irqrestore(&(bdp->bd_lock), lock_flag); - rc = false; - goto exit; - } - - bdp->next_cu_cmd = START_WAIT; - spin_unlock_irqrestore(&(bdp->bd_lock), lock_flag); - - /* now wait for completion of non-cu CB up to 20 msec */ - expiration_time = jiffies + HZ / 50 + 1; - rmb(); - while (!(ntcb_hdr->cb_status & - __constant_cpu_to_le16(CB_STATUS_COMPLETE))) { - - if (time_before(jiffies, expiration_time)) { - spin_unlock_bh(&(bdp->bd_non_tx_lock)); - yield(); - spin_lock_bh(&(bdp->bd_non_tx_lock)); - } else { -#ifdef E100_CU_DEBUG - printk(KERN_ERR "e100: %s: non-TX command (%x) " - "timeout\n", bdp->device->name, sub_cmd); -#endif - rc = false; - goto exit; - } - rmb(); - } - -exit: - e100_free_non_tx_cmd(bdp, command); - - if (netif_running(bdp->device)) - netif_wake_queue(bdp->device); - - spin_unlock_bh(&(bdp->bd_non_tx_lock)); - return rc; - -delayed_exec: - spin_unlock_bh(&(bdp->bd_non_tx_lock)); - return e100_delayed_exec_non_cu_cmd(bdp, command); -} - -/** - * e100_sw_reset - * @bdp: atapter's private data struct - * @reset_cmd: s/w reset or selective reset - * - * This routine will issue a software reset to the adapter. It - * will also disable interrupts, as the are enabled after reset. - */ -void -e100_sw_reset(struct e100_private *bdp, u32 reset_cmd) -{ - /* Do a selective reset first to avoid a potential PCI hang */ - writel(PORT_SELECTIVE_RESET, &bdp->scb->scb_port); - readw(&(bdp->scb->scb_status)); /* flushes last write, read-safe */ - - /* wait for the reset to take effect */ - udelay(20); - if (reset_cmd == PORT_SOFTWARE_RESET) { - writel(PORT_SOFTWARE_RESET, &bdp->scb->scb_port); - - /* wait 20 micro seconds for the reset to take effect */ - udelay(20); - } - - /* Mask off our interrupt line -- it is unmasked after reset */ - e100_disable_clear_intr(bdp); -#ifdef E100_CU_DEBUG - bdp->last_cmd = 0; - bdp->last_sub_cmd = 0; -#endif -} - -/** - * e100_load_microcode - Download microsocde to controller. - * @bdp: atapter's private data struct - * - * This routine downloads microcode on to the controller. This - * microcode is available for the 82558/9, 82550. Currently the - * microcode handles interrupt bundling and TCO workaround. - * - * Returns: - * true: if successfull - * false: otherwise - */ -static unsigned char -e100_load_microcode(struct e100_private *bdp) -{ - static struct { - u8 rev_id; - u32 ucode[UCODE_MAX_DWORDS + 1]; - int timer_dword; - int bundle_dword; - int min_size_dword; - } ucode_opts[] = { - { D101A4_REV_ID, - D101_A_RCVBUNDLE_UCODE, - D101_CPUSAVER_TIMER_DWORD, - D101_CPUSAVER_BUNDLE_DWORD, - D101_CPUSAVER_MIN_SIZE_DWORD }, - { D101B0_REV_ID, - D101_B0_RCVBUNDLE_UCODE, - D101_CPUSAVER_TIMER_DWORD, - D101_CPUSAVER_BUNDLE_DWORD, - D101_CPUSAVER_MIN_SIZE_DWORD }, - { D101MA_REV_ID, - D101M_B_RCVBUNDLE_UCODE, - D101M_CPUSAVER_TIMER_DWORD, - D101M_CPUSAVER_BUNDLE_DWORD, - D101M_CPUSAVER_MIN_SIZE_DWORD }, - { D101S_REV_ID, - D101S_RCVBUNDLE_UCODE, - D101S_CPUSAVER_TIMER_DWORD, - D101S_CPUSAVER_BUNDLE_DWORD, - D101S_CPUSAVER_MIN_SIZE_DWORD }, - { D102_REV_ID, - D102_B_RCVBUNDLE_UCODE, - D102_B_CPUSAVER_TIMER_DWORD, - D102_B_CPUSAVER_BUNDLE_DWORD, - D102_B_CPUSAVER_MIN_SIZE_DWORD }, - { D102C_REV_ID, - D102_C_RCVBUNDLE_UCODE, - D102_C_CPUSAVER_TIMER_DWORD, - D102_C_CPUSAVER_BUNDLE_DWORD, - D102_C_CPUSAVER_MIN_SIZE_DWORD }, - { D102E_REV_ID, - D102_E_RCVBUNDLE_UCODE, - D102_E_CPUSAVER_TIMER_DWORD, - D102_E_CPUSAVER_BUNDLE_DWORD, - D102_E_CPUSAVER_MIN_SIZE_DWORD }, - { 0, {0}, 0, 0, 0} - }, *opts; - - opts = ucode_opts; - - /* User turned ucode loading off */ - if (!(bdp->params.b_params & PRM_UCODE)) - return false; - - /* These controllers do not need ucode */ - if (bdp->flags & IS_ICH) - return false; - - /* Search for ucode match against h/w rev_id */ - while (opts->rev_id) { - if (bdp->rev_id == opts->rev_id) { - int i; - u32 *ucode_dword; - load_ucode_cb_t *ucode_cmd_ptr; - nxmit_cb_entry_t *cmd = e100_alloc_non_tx_cmd(bdp); - - if (cmd != NULL) { - ucode_cmd_ptr = - (load_ucode_cb_t *) cmd->non_tx_cmd; - ucode_dword = ucode_cmd_ptr->ucode_dword; - } else { - return false; - } - - memcpy(ucode_dword, opts->ucode, sizeof (opts->ucode)); - - /* Insert user-tunable settings */ - ucode_dword[opts->timer_dword] &= 0xFFFF0000; - ucode_dword[opts->timer_dword] |= - (u16) bdp->params.IntDelay; - ucode_dword[opts->bundle_dword] &= 0xFFFF0000; - ucode_dword[opts->bundle_dword] |= - (u16) bdp->params.BundleMax; - ucode_dword[opts->min_size_dword] &= 0xFFFF0000; - ucode_dword[opts->min_size_dword] |= - (bdp->params.b_params & PRM_BUNDLE_SMALL) ? - 0xFFFF : 0xFF80; - - for (i = 0; i < UCODE_MAX_DWORDS; i++) - cpu_to_le32s(&(ucode_dword[i])); - - ucode_cmd_ptr->load_ucode_cbhdr.cb_cmd = - __constant_cpu_to_le16(CB_LOAD_MICROCODE); - - return e100_exec_non_cu_cmd(bdp, cmd); - } - opts++; - } - - return false; -} - -/***************************************************************************/ -/***************************************************************************/ -/* EEPROM Functions */ -/***************************************************************************/ - -/* Read PWA (printed wired assembly) number */ -void -e100_rd_pwa_no(struct e100_private *bdp) -{ - bdp->pwa_no = e100_eeprom_read(bdp, EEPROM_PWA_NO); - bdp->pwa_no <<= 16; - bdp->pwa_no |= e100_eeprom_read(bdp, EEPROM_PWA_NO + 1); -} - -/* Read the permanent ethernet address from the eprom. */ -void -e100_rd_eaddr(struct e100_private *bdp) -{ - int i; - u16 eeprom_word; - - for (i = 0; i < 6; i += 2) { - eeprom_word = - e100_eeprom_read(bdp, - EEPROM_NODE_ADDRESS_BYTE_0 + (i / 2)); - - bdp->device->dev_addr[i] = - bdp->perm_node_address[i] = (u8) eeprom_word; - bdp->device->dev_addr[i + 1] = - bdp->perm_node_address[i + 1] = (u8) (eeprom_word >> 8); - } -} - -/* Check the D102 RFD flags to see if the checksum passed */ -static unsigned char -e100_D102_check_checksum(rfd_t *rfd) -{ - if (((le16_to_cpu(rfd->rfd_header.cb_status)) & RFD_PARSE_BIT) - && (((rfd->rcvparserstatus & CHECKSUM_PROTOCOL_MASK) == - RFD_TCP_PACKET) - || ((rfd->rcvparserstatus & CHECKSUM_PROTOCOL_MASK) == - RFD_UDP_PACKET)) - && (rfd->checksumstatus & TCPUDP_CHECKSUM_BIT_VALID) - && (rfd->checksumstatus & TCPUDP_CHECKSUM_VALID)) { - return CHECKSUM_UNNECESSARY; - } - return CHECKSUM_NONE; -} - -/** - * e100_D101M_checksum - * @bdp: atapter's private data struct - * @skb: skb received - * - * Sets the skb->csum value from D101 csum found at the end of the Rx frame. The - * D101M sums all words in frame excluding the ethernet II header (14 bytes) so - * in case the packet is ethernet II and the protocol is IP, all is need is to - * assign this value to skb->csum. - */ -static unsigned char -e100_D101M_checksum(struct e100_private *bdp, struct sk_buff *skb) -{ - unsigned short proto = (skb->protocol); - - if (proto == __constant_htons(ETH_P_IP)) { - - skb->csum = get_unaligned((u16 *) (skb->tail)); - return CHECKSUM_HW; - } - return CHECKSUM_NONE; -} - -/***************************************************************************/ -/***************************************************************************/ -/***************************************************************************/ -/***************************************************************************/ -/* Auxilary Functions */ -/***************************************************************************/ - -/* Print the board's configuration */ -void -e100_print_brd_conf(struct e100_private *bdp) -{ - /* Print the string if checksum Offloading was enabled */ - if (bdp->flags & DF_CSUM_OFFLOAD) - printk(KERN_NOTICE " Hardware receive checksums enabled\n"); - else { - if (bdp->rev_id >= D101MA_REV_ID) - printk(KERN_NOTICE " Hardware receive checksums disabled\n"); - } - - if ((bdp->flags & DF_UCODE_LOADED)) - printk(KERN_NOTICE " cpu cycle saver enabled\n"); -} - -/** - * e100_pci_setup - setup the adapter's PCI information - * @pcid: adapter's pci_dev struct - * @bdp: atapter's private data struct - * - * This routine sets up all PCI information for the adapter. It enables the bus - * master bit (some BIOS don't do this), requests memory ans I/O regions, and - * calls ioremap() on the adapter's memory region. - * - * Returns: - * true: if successfull - * false: otherwise - */ -static unsigned char -e100_pci_setup(struct pci_dev *pcid, struct e100_private *bdp) -{ - struct net_device *dev = bdp->device; - int rc = 0; - - if ((rc = pci_enable_device(pcid)) != 0) { - goto err; - } - - /* dev and ven ID have already been checked so it is our device */ - pci_read_config_byte(pcid, PCI_REVISION_ID, (u8 *) &(bdp->rev_id)); - - /* address #0 is a memory region */ - dev->mem_start = pci_resource_start(pcid, 0); - dev->mem_end = dev->mem_start + sizeof (scb_t); - - /* address #1 is a IO region */ - dev->base_addr = pci_resource_start(pcid, 1); - - if ((rc = pci_request_regions(pcid, e100_short_driver_name)) != 0) { - goto err_disable; - } - - pci_enable_wake(pcid, 0, 0); - - /* if Bus Mastering is off, turn it on! */ - pci_set_master(pcid); - - /* address #0 is a memory mapping */ - bdp->scb = (scb_t *) ioremap_nocache(dev->mem_start, sizeof (scb_t)); - - if (!bdp->scb) { - printk(KERN_ERR "e100: %s: Failed to map PCI address 0x%lX\n", - dev->name, pci_resource_start(pcid, 0)); - rc = -ENOMEM; - goto err_region; - } - - return 0; - -err_region: - pci_release_regions(pcid); -err_disable: - pci_disable_device(pcid); -err: - return rc; -} - -void -e100_isolate_driver(struct e100_private *bdp) -{ - - /* Check if interface is up */ - /* NOTE: Can't use netif_running(bdp->device) because */ - /* dev_close clears __LINK_STATE_START before calling */ - /* e100_close (aka dev->stop) */ - if (bdp->device->flags & IFF_UP) { - e100_disable_clear_intr(bdp); - del_timer_sync(&bdp->watchdog_timer); - netif_carrier_off(bdp->device); - netif_stop_queue(bdp->device); - bdp->last_tcb = NULL; - } - e100_sw_reset(bdp, PORT_SELECTIVE_RESET); -} - -static void -e100_tcb_add_C_bit(struct e100_private *bdp) -{ - tcb_t *tcb = (tcb_t *) bdp->tcb_pool.data; - int i; - - for (i = 0; i < bdp->params.TxDescriptors; i++, tcb++) { - tcb->tcb_hdr.cb_status |= cpu_to_le16(CB_STATUS_COMPLETE); - } -} - -/* - * Procedure: e100_configure_device - * - * Description: This routine will configure device - * - * Arguments: - * bdp - Ptr to this card's e100_bdconfig structure - * - * Returns: - * true upon success - * false upon failure - */ -unsigned char -e100_configure_device(struct e100_private *bdp) -{ - /*load CU & RU base */ - if (!e100_wait_exec_cmplx(bdp, 0, SCB_CUC_LOAD_BASE, 0)) - return false; - - if (e100_load_microcode(bdp)) - bdp->flags |= DF_UCODE_LOADED; - - if (!e100_wait_exec_cmplx(bdp, 0, SCB_RUC_LOAD_BASE, 0)) - return false; - - /* Issue the load dump counters address command */ - if (!e100_wait_exec_cmplx(bdp, bdp->stat_cnt_phys, SCB_CUC_DUMP_ADDR, 0)) - return false; - - if (!e100_setup_iaaddr(bdp, bdp->device->dev_addr)) { - printk(KERN_ERR "e100: e100_configure_device: " - "setup iaaddr failed\n"); - return false; - } - - e100_set_multi_exec(bdp->device); - - /* Change for 82558 enhancement */ - /* If 82558/9 and if the user has enabled flow control, set up */ - /* flow Control Reg. in the CSR */ - if ((bdp->flags & IS_BACHELOR) - && (bdp->params.b_params & PRM_FC)) { - writeb(DFLT_FC_THLD, - &bdp->scb->scb_ext.d101_scb.scb_fc_thld); - writeb(DFLT_FC_CMD, - &bdp->scb->scb_ext.d101_scb.scb_fc_xon_xoff); - } - - e100_force_config(bdp); - - return true; -} - -void -e100_deisolate_driver(struct e100_private *bdp, u8 full_reset) -{ - u32 cmd = full_reset ? PORT_SOFTWARE_RESET : PORT_SELECTIVE_RESET; - e100_sw_reset(bdp, cmd); - if (cmd == PORT_SOFTWARE_RESET) { - if (!e100_configure_device(bdp)) - printk(KERN_ERR "e100: e100_deisolate_driver:" - " device configuration failed\n"); - } - - if (netif_running(bdp->device)) { - - bdp->next_cu_cmd = START_WAIT; - bdp->last_tcb = NULL; - - e100_start_ru(bdp); - - /* relaunch watchdog timer in 2 sec */ - mod_timer(&(bdp->watchdog_timer), jiffies + (2 * HZ)); - - // we must clear tcbs since we may have lost Tx intrrupt - // or have unsent frames on the tcb chain - e100_tcb_add_C_bit(bdp); - e100_tx_srv(bdp); - netif_wake_queue(bdp->device); - e100_set_intr_mask(bdp); - } -} - -static int -e100_do_ethtool_ioctl(struct net_device *dev, struct ifreq *ifr) -{ - struct ethtool_cmd ecmd; - int rc = -EOPNOTSUPP; - - if (copy_from_user(&ecmd, ifr->ifr_data, sizeof (ecmd.cmd))) - return -EFAULT; - - switch (ecmd.cmd) { - case ETHTOOL_GSET: - rc = e100_ethtool_get_settings(dev, ifr); - break; - case ETHTOOL_SSET: - rc = e100_ethtool_set_settings(dev, ifr); - break; - case ETHTOOL_GDRVINFO: - rc = e100_ethtool_get_drvinfo(dev, ifr); - break; - case ETHTOOL_GREGS: - rc = e100_ethtool_gregs(dev, ifr); - break; - case ETHTOOL_NWAY_RST: - rc = e100_ethtool_nway_rst(dev, ifr); - break; - case ETHTOOL_GLINK: - rc = e100_ethtool_glink(dev, ifr); - break; - case ETHTOOL_GEEPROM: - case ETHTOOL_SEEPROM: - rc = e100_ethtool_eeprom(dev, ifr); - break; - case ETHTOOL_GSTATS: { - struct { - struct ethtool_stats cmd; - uint64_t data[E100_STATS_LEN]; - } stats = { {ETHTOOL_GSTATS, E100_STATS_LEN} }; - struct e100_private *bdp = dev->priv; - void *addr = ifr->ifr_data; - int i; - - for(i = 0; i < E100_STATS_LEN; i++) - stats.data[i] = - ((unsigned long *)&bdp->drv_stats.net_stats)[i]; - if(copy_to_user(addr, &stats, sizeof(stats))) - return -EFAULT; - return 0; - } - case ETHTOOL_GWOL: - case ETHTOOL_SWOL: - rc = e100_ethtool_wol(dev, ifr); - break; - case ETHTOOL_TEST: - rc = e100_ethtool_test(dev, ifr); - break; - case ETHTOOL_GSTRINGS: - rc = e100_ethtool_gstrings(dev,ifr); - break; - case ETHTOOL_PHYS_ID: - rc = e100_ethtool_led_blink(dev,ifr); - break; -#ifdef ETHTOOL_GRINGPARAM - case ETHTOOL_GRINGPARAM: { - struct ethtool_ringparam ering; - struct e100_private *bdp = dev->priv; - memset((void *) &ering, 0, sizeof(ering)); - ering.rx_max_pending = E100_MAX_RFD; - ering.tx_max_pending = E100_MAX_TCB; - ering.rx_pending = bdp->params.RxDescriptors; - ering.tx_pending = bdp->params.TxDescriptors; - rc = copy_to_user(ifr->ifr_data, &ering, sizeof(ering)) - ? -EFAULT : 0; - return rc; - } -#endif -#ifdef ETHTOOL_SRINGPARAM - case ETHTOOL_SRINGPARAM: { - struct ethtool_ringparam ering; - struct e100_private *bdp = dev->priv; - if (copy_from_user(&ering, ifr->ifr_data, sizeof(ering))) - return -EFAULT; - if (ering.rx_pending > E100_MAX_RFD - || ering.rx_pending < E100_MIN_RFD) - return -EINVAL; - if (ering.tx_pending > E100_MAX_TCB - || ering.tx_pending < E100_MIN_TCB) - return -EINVAL; - if (netif_running(dev)) { - spin_lock_bh(&dev->xmit_lock); - e100_close(dev); - spin_unlock_bh(&dev->xmit_lock); - /* Use new values to open interface */ - bdp->params.RxDescriptors = ering.rx_pending; - bdp->params.TxDescriptors = ering.tx_pending; - e100_hw_init(bdp); - e100_open(dev); - } - else { - bdp->params.RxDescriptors = ering.rx_pending; - bdp->params.TxDescriptors = ering.tx_pending; - } - return 0; - } -#endif -#ifdef ETHTOOL_GPAUSEPARAM - case ETHTOOL_GPAUSEPARAM: { - struct ethtool_pauseparam epause; - struct e100_private *bdp = dev->priv; - memset((void *) &epause, 0, sizeof(epause)); - if ((bdp->flags & IS_BACHELOR) - && (bdp->params.b_params & PRM_FC)) { - epause.autoneg = 1; - if (bdp->flags && DF_LINK_FC_CAP) { - epause.rx_pause = 1; - epause.tx_pause = 1; - } - if (bdp->flags && DF_LINK_FC_TX_ONLY) - epause.tx_pause = 1; - } - rc = copy_to_user(ifr->ifr_data, &epause, sizeof(epause)) - ? -EFAULT : 0; - return rc; - } -#endif -#ifdef ETHTOOL_SPAUSEPARAM - case ETHTOOL_SPAUSEPARAM: { - struct ethtool_pauseparam epause; - struct e100_private *bdp = dev->priv; - if (!(bdp->flags & IS_BACHELOR)) - return -EINVAL; - if (copy_from_user(&epause, ifr->ifr_data, sizeof(epause))) - return -EFAULT; - if (epause.autoneg == 1) - bdp->params.b_params |= PRM_FC; - else - bdp->params.b_params &= ~PRM_FC; - if (netif_running(dev)) { - spin_lock_bh(&dev->xmit_lock); - e100_close(dev); - spin_unlock_bh(&dev->xmit_lock); - e100_hw_init(bdp); - e100_open(dev); - } - return 0; - } -#endif -#ifdef ETHTOOL_GRXCSUM - case ETHTOOL_GRXCSUM: - case ETHTOOL_GTXCSUM: - case ETHTOOL_GSG: - { struct ethtool_value eval; - struct e100_private *bdp = dev->priv; - memset((void *) &eval, 0, sizeof(eval)); - if ((ecmd.cmd == ETHTOOL_GRXCSUM) - && (bdp->params.b_params & PRM_XSUMRX)) - eval.data = 1; - else - eval.data = 0; - rc = copy_to_user(ifr->ifr_data, &eval, sizeof(eval)) - ? -EFAULT : 0; - return rc; - } -#endif -#ifdef ETHTOOL_SRXCSUM - case ETHTOOL_SRXCSUM: - case ETHTOOL_STXCSUM: - case ETHTOOL_SSG: - { struct ethtool_value eval; - struct e100_private *bdp = dev->priv; - if (copy_from_user(&eval, ifr->ifr_data, sizeof(eval))) - return -EFAULT; - if (ecmd.cmd == ETHTOOL_SRXCSUM) { - if (eval.data == 1) { - if (bdp->rev_id >= D101MA_REV_ID) - bdp->params.b_params |= PRM_XSUMRX; - else - return -EINVAL; - } else { - if (bdp->rev_id >= D101MA_REV_ID) - bdp->params.b_params &= ~PRM_XSUMRX; - else - return 0; - } - } else { - if (eval.data == 1) - return -EINVAL; - else - return 0; - } - if (netif_running(dev)) { - spin_lock_bh(&dev->xmit_lock); - e100_close(dev); - spin_unlock_bh(&dev->xmit_lock); - e100_hw_init(bdp); - e100_open(dev); - } - return 0; - } -#endif - default: - break; - } //switch - return rc; -} - -static int -e100_ethtool_get_settings(struct net_device *dev, struct ifreq *ifr) -{ - struct e100_private *bdp; - struct ethtool_cmd ecmd; - u16 advert = 0; - - memset((void *) &ecmd, 0, sizeof (ecmd)); - - bdp = dev->priv; - - ecmd.supported = bdp->speed_duplex_caps; - - ecmd.port = - (bdp->speed_duplex_caps & SUPPORTED_TP) ? PORT_TP : PORT_FIBRE; - ecmd.transceiver = XCVR_INTERNAL; - ecmd.phy_address = bdp->phy_addr; - - if (netif_carrier_ok(bdp->device)) { - ecmd.speed = bdp->cur_line_speed; - ecmd.duplex = - (bdp->cur_dplx_mode == HALF_DUPLEX) ? DUPLEX_HALF : DUPLEX_FULL; - } - else { - ecmd.speed = -1; - ecmd.duplex = -1; - } - - ecmd.advertising = ADVERTISED_TP; - - if (bdp->params.e100_speed_duplex == E100_AUTONEG) { - ecmd.autoneg = AUTONEG_ENABLE; - ecmd.advertising |= ADVERTISED_Autoneg; - } else { - ecmd.autoneg = AUTONEG_DISABLE; - } - - if (bdp->speed_duplex_caps & SUPPORTED_MII) { - e100_mdi_read(bdp, MII_ADVERTISE, bdp->phy_addr, &advert); - - if (advert & ADVERTISE_10HALF) - ecmd.advertising |= ADVERTISED_10baseT_Half; - if (advert & ADVERTISE_10FULL) - ecmd.advertising |= ADVERTISED_10baseT_Full; - if (advert & ADVERTISE_100HALF) - ecmd.advertising |= ADVERTISED_100baseT_Half; - if (advert & ADVERTISE_100FULL) - ecmd.advertising |= ADVERTISED_100baseT_Full; - } else { - ecmd.autoneg = AUTONEG_DISABLE; - ecmd.advertising &= ~ADVERTISED_Autoneg; - } - - if (copy_to_user(ifr->ifr_data, &ecmd, sizeof (ecmd))) - return -EFAULT; - - return 0; -} - -static int -e100_ethtool_set_settings(struct net_device *dev, struct ifreq *ifr) -{ - struct e100_private *bdp; - int e100_new_speed_duplex; - int ethtool_new_speed_duplex; - struct ethtool_cmd ecmd; - - bdp = dev->priv; - if (copy_from_user(&ecmd, ifr->ifr_data, sizeof (ecmd))) { - return -EFAULT; - } - - if ((ecmd.autoneg == AUTONEG_ENABLE) - && (bdp->speed_duplex_caps & SUPPORTED_Autoneg)) { - bdp->params.e100_speed_duplex = E100_AUTONEG; - if (netif_running(dev)) { - spin_lock_bh(&dev->xmit_lock); - e100_close(dev); - spin_unlock_bh(&dev->xmit_lock); - e100_hw_init(bdp); - e100_open(dev); - } - } else { - if (ecmd.speed == SPEED_10) { - if (ecmd.duplex == DUPLEX_HALF) { - e100_new_speed_duplex = - E100_SPEED_10_HALF; - ethtool_new_speed_duplex = - SUPPORTED_10baseT_Half; - } else { - e100_new_speed_duplex = - E100_SPEED_10_FULL; - ethtool_new_speed_duplex = - SUPPORTED_10baseT_Full; - } - } else { - if (ecmd.duplex == DUPLEX_HALF) { - e100_new_speed_duplex = - E100_SPEED_100_HALF; - ethtool_new_speed_duplex = - SUPPORTED_100baseT_Half; - } else { - e100_new_speed_duplex = - E100_SPEED_100_FULL; - ethtool_new_speed_duplex = - SUPPORTED_100baseT_Full; - } - } - - if (bdp->speed_duplex_caps & ethtool_new_speed_duplex) { - bdp->params.e100_speed_duplex = - e100_new_speed_duplex; - if (netif_running(dev)) { - spin_lock_bh(&dev->xmit_lock); - e100_close(dev); - spin_unlock_bh(&dev->xmit_lock); - e100_hw_init(bdp); - e100_open(dev); - } - } else { - return -EOPNOTSUPP; - } - } - - return 0; -} - -static int -e100_ethtool_glink(struct net_device *dev, struct ifreq *ifr) -{ - struct e100_private *bdp; - struct ethtool_value info; - - memset((void *) &info, 0, sizeof (info)); - - bdp = dev->priv; - info.cmd = ETHTOOL_GLINK; - - /* Consider both PHY link and netif_running */ - info.data = e100_update_link_state(bdp); - - if (copy_to_user(ifr->ifr_data, &info, sizeof (info))) - return -EFAULT; - - return 0; -} - -static int -e100_ethtool_test(struct net_device *dev, struct ifreq *ifr) -{ - struct ethtool_test *info; - int rc = -EFAULT; - - info = kmalloc(sizeof(*info) + max_test_res * sizeof(u64), - GFP_ATOMIC); - - if (!info) - return -ENOMEM; - - memset((void *) info, 0, sizeof(*info) + - max_test_res * sizeof(u64)); - - if (copy_from_user(info, ifr->ifr_data, sizeof(*info))) - goto exit; - - info->flags = e100_run_diag(dev, info->data, info->flags); - - if (!copy_to_user(ifr->ifr_data, info, - sizeof(*info) + max_test_res * sizeof(u64))) - rc = 0; -exit: - kfree(info); - return rc; -} - -static int -e100_ethtool_gregs(struct net_device *dev, struct ifreq *ifr) -{ - struct e100_private *bdp; - u32 regs_buff[E100_REGS_LEN]; - struct ethtool_regs regs = {ETHTOOL_GREGS}; - void *addr = ifr->ifr_data; - u16 mdi_reg; - - bdp = dev->priv; - - if(copy_from_user(®s, addr, sizeof(regs))) - return -EFAULT; - - regs.version = (1 << 24) | bdp->rev_id; - regs_buff[0] = readb(&(bdp->scb->scb_cmd_hi)) << 24 | - readb(&(bdp->scb->scb_cmd_low)) << 16 | - readw(&(bdp->scb->scb_status)); - e100_mdi_read(bdp, MII_NCONFIG, bdp->phy_addr, &mdi_reg); - regs_buff[1] = mdi_reg; - - if(copy_to_user(addr, ®s, sizeof(regs))) - return -EFAULT; - - addr += offsetof(struct ethtool_regs, data); - if(copy_to_user(addr, regs_buff, regs.len)) - return -EFAULT; - - return 0; -} - -static int -e100_ethtool_nway_rst(struct net_device *dev, struct ifreq *ifr) -{ - struct e100_private *bdp; - - bdp = dev->priv; - - if ((bdp->speed_duplex_caps & SUPPORTED_Autoneg) && - (bdp->params.e100_speed_duplex == E100_AUTONEG)) { - if (netif_running(dev)) { - spin_lock_bh(&dev->xmit_lock); - e100_close(dev); - spin_unlock_bh(&dev->xmit_lock); - e100_hw_init(bdp); - e100_open(dev); - } - } else { - return -EFAULT; - } - return 0; -} - -static int -e100_ethtool_get_drvinfo(struct net_device *dev, struct ifreq *ifr) -{ - struct e100_private *bdp; - struct ethtool_drvinfo info; - - memset((void *) &info, 0, sizeof (info)); - - bdp = dev->priv; - - strncpy(info.driver, e100_short_driver_name, sizeof (info.driver) - 1); - strncpy(info.version, e100_driver_version, sizeof (info.version) - 1); - strncpy(info.fw_version, "N/A", - sizeof (info.fw_version) - 1); - strncpy(info.bus_info, pci_name(bdp->pdev), - sizeof (info.bus_info) - 1); - info.n_stats = E100_STATS_LEN; - info.regdump_len = E100_REGS_LEN * sizeof(u32); - info.eedump_len = (bdp->eeprom_size << 1); - info.testinfo_len = max_test_res; - if (copy_to_user(ifr->ifr_data, &info, sizeof (info))) - return -EFAULT; - - return 0; -} - -static int -e100_ethtool_eeprom(struct net_device *dev, struct ifreq *ifr) -{ - struct e100_private *bdp; - struct ethtool_eeprom ecmd; - u16 eeprom_data[256]; - u16 *usr_eeprom_ptr; - u16 first_word, last_word; - int i, max_len; - void *ptr; - u8 *eeprom_data_bytes = (u8 *)eeprom_data; - - bdp = dev->priv; - - if (copy_from_user(&ecmd, ifr->ifr_data, sizeof (ecmd))) - return -EFAULT; - - usr_eeprom_ptr = - (u16 *) (ifr->ifr_data + offsetof(struct ethtool_eeprom, data)); - - max_len = bdp->eeprom_size * 2; - - if (ecmd.offset > ecmd.offset + ecmd.len) - return -EINVAL; - - if ((ecmd.offset + ecmd.len) > max_len) - ecmd.len = (max_len - ecmd.offset); - - first_word = ecmd.offset >> 1; - last_word = (ecmd.offset + ecmd.len - 1) >> 1; - - if (first_word >= bdp->eeprom_size) - return -EFAULT; - - if (ecmd.cmd == ETHTOOL_GEEPROM) { - for(i = 0; i <= (last_word - first_word); i++) - eeprom_data[i] = e100_eeprom_read(bdp, first_word + i); - - ecmd.magic = E100_EEPROM_MAGIC; - - if (copy_to_user(ifr->ifr_data, &ecmd, sizeof (ecmd))) - return -EFAULT; - - if(ecmd.offset & 1) - eeprom_data_bytes++; - if (copy_to_user(usr_eeprom_ptr, eeprom_data_bytes, ecmd.len)) - return -EFAULT; - } else { - if (ecmd.magic != E100_EEPROM_MAGIC) - return -EFAULT; - - ptr = (void *)eeprom_data; - if(ecmd.offset & 1) { - /* need modification of first changed EEPROM word */ - /* only the second byte of the word is being modified */ - eeprom_data[0] = e100_eeprom_read(bdp, first_word); - ptr++; - } - if((ecmd.offset + ecmd.len) & 1) { - /* need modification of last changed EEPROM word */ - /* only the first byte of the word is being modified */ - eeprom_data[last_word - first_word] = - e100_eeprom_read(bdp, last_word); - } - if(copy_from_user(ptr, usr_eeprom_ptr, ecmd.len)) - return -EFAULT; - - e100_eeprom_write_block(bdp, first_word, eeprom_data, - last_word - first_word + 1); - - if (copy_to_user(ifr->ifr_data, &ecmd, sizeof (ecmd))) - return -EFAULT; - } - return 0; -} - -#define E100_BLINK_INTERVAL (HZ/4) -/** - * e100_led_control - * @bdp: atapter's private data struct - * @led_mdi_op: led operation - * - * Software control over adapter's led. The possible operations are: - * TURN LED OFF, TURN LED ON and RETURN LED CONTROL TO HARDWARE. - */ -static void -e100_led_control(struct e100_private *bdp, u16 led_mdi_op) -{ - e100_mdi_write(bdp, PHY_82555_LED_SWITCH_CONTROL, - bdp->phy_addr, led_mdi_op); - -} -/** - * e100_led_blink_callback - * @data: pointer to atapter's private data struct - * - * Blink timer callback function. Toggles ON/OFF led status bit and calls - * led hardware access function. - */ -static void -e100_led_blink_callback(unsigned long data) -{ - struct e100_private *bdp = (struct e100_private *) data; - - if(bdp->flags & LED_IS_ON) { - bdp->flags &= ~LED_IS_ON; - e100_led_control(bdp, PHY_82555_LED_OFF); - } else { - bdp->flags |= LED_IS_ON; - if (bdp->rev_id >= D101MA_REV_ID) - e100_led_control(bdp, PHY_82555_LED_ON_559); - else - e100_led_control(bdp, PHY_82555_LED_ON_PRE_559); - } - - mod_timer(&bdp->blink_timer, jiffies + E100_BLINK_INTERVAL); -} -/** - * e100_ethtool_led_blink - * @dev: pointer to atapter's net_device struct - * @ifr: pointer to ioctl request structure - * - * Blink led ioctl handler. Initialtes blink timer and sleeps until - * blink period expires. Than it kills timer and returns. The led control - * is returned back to hardware when blink timer is killed. - */ -static int -e100_ethtool_led_blink(struct net_device *dev, struct ifreq *ifr) -{ - struct e100_private *bdp; - struct ethtool_value ecmd; - - bdp = dev->priv; - - if (copy_from_user(&ecmd, ifr->ifr_data, sizeof (ecmd))) - return -EFAULT; - - if(!bdp->blink_timer.function) { - init_timer(&bdp->blink_timer); - bdp->blink_timer.function = e100_led_blink_callback; - bdp->blink_timer.data = (unsigned long) bdp; - } - - mod_timer(&bdp->blink_timer, jiffies); - - set_current_state(TASK_INTERRUPTIBLE); - - if ((!ecmd.data) || (ecmd.data > (u32)(MAX_SCHEDULE_TIMEOUT / HZ))) - ecmd.data = (u32)(MAX_SCHEDULE_TIMEOUT / HZ); - - schedule_timeout(ecmd.data * HZ); - - del_timer_sync(&bdp->blink_timer); - - e100_led_control(bdp, PHY_82555_LED_NORMAL_CONTROL); - - return 0; -} - -static inline int -e100_10BaseT_adapter(struct e100_private *bdp) -{ - return ((bdp->pdev->device == 0x1229) && - (bdp->pdev->subsystem_vendor == 0x8086) && - (bdp->pdev->subsystem_device == 0x0003)); -} - -static void -e100_get_speed_duplex_caps(struct e100_private *bdp) -{ - u16 status; - - e100_mdi_read(bdp, MII_BMSR, bdp->phy_addr, &status); - - bdp->speed_duplex_caps = 0; - - bdp->speed_duplex_caps |= - (status & BMSR_ANEGCAPABLE) ? SUPPORTED_Autoneg : 0; - - bdp->speed_duplex_caps |= - (status & BMSR_10HALF) ? SUPPORTED_10baseT_Half : 0; - - bdp->speed_duplex_caps |= - (status & BMSR_10FULL) ? SUPPORTED_10baseT_Full : 0; - - bdp->speed_duplex_caps |= - (status & BMSR_100HALF) ? SUPPORTED_100baseT_Half : 0; - - bdp->speed_duplex_caps |= - (status & BMSR_100FULL) ? SUPPORTED_100baseT_Full : 0; - - if (IS_NC3133(bdp)) - bdp->speed_duplex_caps = - (SUPPORTED_FIBRE | SUPPORTED_100baseT_Full); - else - bdp->speed_duplex_caps |= SUPPORTED_TP; - - if ((status == 0xFFFF) && e100_10BaseT_adapter(bdp)) { - bdp->speed_duplex_caps = - (SUPPORTED_10baseT_Half | SUPPORTED_TP); - } else { - bdp->speed_duplex_caps |= SUPPORTED_MII; - } - -} - -#ifdef CONFIG_PM -static unsigned char -e100_setup_filter(struct e100_private *bdp) -{ - cb_header_t *ntcb_hdr; - unsigned char res = false; - nxmit_cb_entry_t *cmd; - - if ((cmd = e100_alloc_non_tx_cmd(bdp)) == NULL) { - goto exit; - } - - ntcb_hdr = (cb_header_t *) cmd->non_tx_cmd; - ntcb_hdr->cb_cmd = __constant_cpu_to_le16(CB_LOAD_FILTER); - - /* Set EL and FIX bit */ - (cmd->non_tx_cmd)->ntcb.filter.filter_data[0] = - __constant_cpu_to_le32(CB_FILTER_EL | CB_FILTER_FIX); - - if (bdp->wolopts & WAKE_UCAST) { - (cmd->non_tx_cmd)->ntcb.filter.filter_data[0] |= - __constant_cpu_to_le32(CB_FILTER_IA_MATCH); - } - - if (bdp->wolopts & WAKE_ARP) { - /* Setup ARP bit and lower IP parts */ - /* bdp->ip_lbytes contains 2 lower bytes of IP address in network byte order */ - (cmd->non_tx_cmd)->ntcb.filter.filter_data[0] |= - cpu_to_le32(CB_FILTER_ARP | bdp->ip_lbytes); - } - - res = e100_exec_non_cu_cmd(bdp, cmd); - if (!res) - printk(KERN_WARNING "e100: %s: Filter setup failed\n", - bdp->device->name); - -exit: - return res; - -} - -static void -e100_do_wol(struct pci_dev *pcid, struct e100_private *bdp) -{ - e100_config_wol(bdp); - - if (e100_config(bdp)) { - if (bdp->wolopts & (WAKE_UCAST | WAKE_ARP)) - if (!e100_setup_filter(bdp)) - printk(KERN_ERR - "e100: WOL options failed\n"); - } else { - printk(KERN_ERR "e100: config WOL failed\n"); - } -} -#endif - -static u16 -e100_get_ip_lbytes(struct net_device *dev) -{ - struct in_ifaddr *ifa; - struct in_device *in_dev; - u32 res = 0; - - in_dev = (struct in_device *) dev->ip_ptr; - /* Check if any in_device bound to interface */ - if (in_dev) { - /* Check if any IP address is bound to interface */ - if ((ifa = in_dev->ifa_list) != NULL) { - res = __constant_ntohl(ifa->ifa_address); - res = __constant_htons(res & 0x0000ffff); - } - } - return res; -} - -static int -e100_ethtool_wol(struct net_device *dev, struct ifreq *ifr) -{ - struct e100_private *bdp; - struct ethtool_wolinfo wolinfo; - int res = 0; - - bdp = dev->priv; - - if (copy_from_user(&wolinfo, ifr->ifr_data, sizeof (wolinfo))) { - return -EFAULT; - } - - switch (wolinfo.cmd) { - case ETHTOOL_GWOL: - wolinfo.supported = bdp->wolsupported; - wolinfo.wolopts = bdp->wolopts; - if (copy_to_user(ifr->ifr_data, &wolinfo, sizeof (wolinfo))) - res = -EFAULT; - break; - case ETHTOOL_SWOL: - /* If ALL requests are supported or request is DISABLE wol */ - if (((wolinfo.wolopts & bdp->wolsupported) == wolinfo.wolopts) - || (wolinfo.wolopts == 0)) { - bdp->wolopts = wolinfo.wolopts; - } else { - res = -EOPNOTSUPP; - } - if (wolinfo.wolopts & WAKE_ARP) - bdp->ip_lbytes = e100_get_ip_lbytes(dev); - break; - default: - break; - } - return res; -} - -static int e100_ethtool_gstrings(struct net_device *dev, struct ifreq *ifr) -{ - struct ethtool_gstrings info; - char *strings = NULL; - char *usr_strings; - int i; - - memset((void *) &info, 0, sizeof(info)); - - usr_strings = (u8 *) (ifr->ifr_data + - offsetof(struct ethtool_gstrings, data)); - - if (copy_from_user(&info, ifr->ifr_data, sizeof (info))) - return -EFAULT; - - switch (info.string_set) { - case ETH_SS_TEST: { - int ret = 0; - if (info.len > max_test_res) - info.len = max_test_res; - strings = kmalloc(info.len * ETH_GSTRING_LEN, GFP_ATOMIC); - if (!strings) - return -ENOMEM; - memset(strings, 0, info.len * ETH_GSTRING_LEN); - - for (i = 0; i < info.len; i++) { - sprintf(strings + i * ETH_GSTRING_LEN, "%s", - test_strings[i]); - } - if (copy_to_user(ifr->ifr_data, &info, sizeof (info))) - ret = -EFAULT; - if (copy_to_user(usr_strings, strings, info.len * ETH_GSTRING_LEN)) - ret = -EFAULT; - kfree(strings); - return ret; - } - case ETH_SS_STATS: { - char *strings = NULL; - void *addr = ifr->ifr_data; - info.len = E100_STATS_LEN; - strings = *e100_gstrings_stats; - if(copy_to_user(ifr->ifr_data, &info, sizeof(info))) - return -EFAULT; - addr += offsetof(struct ethtool_gstrings, data); - if(copy_to_user(addr, strings, - info.len * ETH_GSTRING_LEN)) - return -EFAULT; - return 0; - } - default: - return -EOPNOTSUPP; - } -} - -static int -e100_mii_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) -{ - struct e100_private *bdp; - struct mii_ioctl_data *data_ptr = - (struct mii_ioctl_data *) &(ifr->ifr_data); - - bdp = dev->priv; - - switch (cmd) { - case SIOCGMIIPHY: - data_ptr->phy_id = bdp->phy_addr & 0x1f; - break; - - case SIOCGMIIREG: - if (!capable(CAP_NET_ADMIN)) - return -EPERM; - e100_mdi_read(bdp, data_ptr->reg_num & 0x1f, bdp->phy_addr, - &(data_ptr->val_out)); - break; - - case SIOCSMIIREG: - if (!capable(CAP_NET_ADMIN)) - return -EPERM; - /* If reg = 0 && change speed/duplex */ - if (data_ptr->reg_num == 0 && - (data_ptr->val_in == (BMCR_ANENABLE | BMCR_ANRESTART) /* restart cmd */ - || data_ptr->val_in == (BMCR_RESET) /* reset cmd */ - || data_ptr->val_in & (BMCR_SPEED100 | BMCR_FULLDPLX) - || data_ptr->val_in == 0)) { - if (data_ptr->val_in == (BMCR_ANENABLE | BMCR_ANRESTART) - || data_ptr->val_in == (BMCR_RESET)) - bdp->params.e100_speed_duplex = E100_AUTONEG; - else if (data_ptr->val_in == (BMCR_SPEED100 | BMCR_FULLDPLX)) - bdp->params.e100_speed_duplex = E100_SPEED_100_FULL; - else if (data_ptr->val_in == (BMCR_SPEED100)) - bdp->params.e100_speed_duplex = E100_SPEED_100_HALF; - else if (data_ptr->val_in == (BMCR_FULLDPLX)) - bdp->params.e100_speed_duplex = E100_SPEED_10_FULL; - else - bdp->params.e100_speed_duplex = E100_SPEED_10_HALF; - if (netif_running(dev)) { - spin_lock_bh(&dev->xmit_lock); - e100_close(dev); - spin_unlock_bh(&dev->xmit_lock); - e100_hw_init(bdp); - e100_open(dev); - } - } - else - /* Only allows changing speed/duplex */ - return -EINVAL; - - break; - - default: - return -EOPNOTSUPP; - } - return 0; -} - -nxmit_cb_entry_t * -e100_alloc_non_tx_cmd(struct e100_private *bdp) -{ - nxmit_cb_entry_t *non_tx_cmd_elem; - - if (!(non_tx_cmd_elem = (nxmit_cb_entry_t *) - kmalloc(sizeof (nxmit_cb_entry_t), GFP_ATOMIC))) { - return NULL; - } - non_tx_cmd_elem->non_tx_cmd = - pci_alloc_consistent(bdp->pdev, sizeof (nxmit_cb_t), - &(non_tx_cmd_elem->dma_addr)); - if (non_tx_cmd_elem->non_tx_cmd == NULL) { - kfree(non_tx_cmd_elem); - return NULL; - } - return non_tx_cmd_elem; -} - -void -e100_free_non_tx_cmd(struct e100_private *bdp, - nxmit_cb_entry_t *non_tx_cmd_elem) -{ - pci_free_consistent(bdp->pdev, sizeof (nxmit_cb_t), - non_tx_cmd_elem->non_tx_cmd, - non_tx_cmd_elem->dma_addr); - kfree(non_tx_cmd_elem); -} - -static void -e100_free_nontx_list(struct e100_private *bdp) -{ - nxmit_cb_entry_t *command; - int i; - - while (!list_empty(&bdp->non_tx_cmd_list)) { - command = list_entry(bdp->non_tx_cmd_list.next, - nxmit_cb_entry_t, list_elem); - list_del(&(command->list_elem)); - e100_free_non_tx_cmd(bdp, command); - } - - for (i = 0; i < CB_MAX_NONTX_CMD; i++) { - bdp->same_cmd_entry[i] = NULL; - } -} - -static unsigned char -e100_delayed_exec_non_cu_cmd(struct e100_private *bdp, - nxmit_cb_entry_t *command) -{ - nxmit_cb_entry_t *same_command; - cb_header_t *ntcb_hdr; - u16 cmd; - - ntcb_hdr = (cb_header_t *) command->non_tx_cmd; - - cmd = CB_CMD_MASK & le16_to_cpu(ntcb_hdr->cb_cmd); - - spin_lock_bh(&(bdp->bd_non_tx_lock)); - - same_command = bdp->same_cmd_entry[cmd]; - - if (same_command != NULL) { - memcpy((void *) (same_command->non_tx_cmd), - (void *) (command->non_tx_cmd), sizeof (nxmit_cb_t)); - e100_free_non_tx_cmd(bdp, command); - } else { - list_add_tail(&(command->list_elem), &(bdp->non_tx_cmd_list)); - bdp->same_cmd_entry[cmd] = command; - } - - if (bdp->non_tx_command_state == E100_NON_TX_IDLE) { - bdp->non_tx_command_state = E100_WAIT_TX_FINISH; - mod_timer(&(bdp->nontx_timer_id), jiffies + 1); - } - - spin_unlock_bh(&(bdp->bd_non_tx_lock)); - return true; -} - -static void -e100_non_tx_background(unsigned long ptr) -{ - struct e100_private *bdp = (struct e100_private *) ptr; - nxmit_cb_entry_t *active_command; - int restart = true; - cb_header_t *non_tx_cmd; - u8 sub_cmd; - - spin_lock_bh(&(bdp->bd_non_tx_lock)); - - switch (bdp->non_tx_command_state) { - case E100_WAIT_TX_FINISH: - if (bdp->last_tcb != NULL) { - rmb(); - if ((bdp->last_tcb->tcb_hdr.cb_status & - __constant_cpu_to_le16(CB_STATUS_COMPLETE)) == 0) - goto exit; - } - if ((readw(&bdp->scb->scb_status) & SCB_CUS_MASK) == - SCB_CUS_ACTIVE) { - goto exit; - } - break; - - case E100_WAIT_NON_TX_FINISH: - active_command = list_entry(bdp->non_tx_cmd_list.next, - nxmit_cb_entry_t, list_elem); - rmb(); - - if (((((cb_header_t *) (active_command->non_tx_cmd))->cb_status - & __constant_cpu_to_le16(CB_STATUS_COMPLETE)) == 0) - && time_before(jiffies, active_command->expiration_time)) { - goto exit; - } else { - non_tx_cmd = (cb_header_t *) active_command->non_tx_cmd; - sub_cmd = CB_CMD_MASK & le16_to_cpu(non_tx_cmd->cb_cmd); -#ifdef E100_CU_DEBUG - if (!(non_tx_cmd->cb_status - & __constant_cpu_to_le16(CB_STATUS_COMPLETE))) - printk(KERN_ERR "e100: %s: Queued " - "command (%x) timeout\n", - bdp->device->name, sub_cmd); -#endif - list_del(&(active_command->list_elem)); - e100_free_non_tx_cmd(bdp, active_command); - } - break; - - default: - break; - } //switch - - if (list_empty(&bdp->non_tx_cmd_list)) { - bdp->non_tx_command_state = E100_NON_TX_IDLE; - spin_lock_irq(&(bdp->bd_lock)); - bdp->next_cu_cmd = START_WAIT; - spin_unlock_irq(&(bdp->bd_lock)); - restart = false; - goto exit; - } else { - u16 cmd_type; - - bdp->non_tx_command_state = E100_WAIT_NON_TX_FINISH; - active_command = list_entry(bdp->non_tx_cmd_list.next, - nxmit_cb_entry_t, list_elem); - sub_cmd = ((cb_header_t *) active_command->non_tx_cmd)->cb_cmd; - spin_lock_irq(&(bdp->bd_lock)); - e100_wait_exec_cmplx(bdp, active_command->dma_addr, - SCB_CUC_START, sub_cmd); - spin_unlock_irq(&(bdp->bd_lock)); - active_command->expiration_time = jiffies + HZ; - cmd_type = CB_CMD_MASK & - le16_to_cpu(((cb_header_t *) - (active_command->non_tx_cmd))->cb_cmd); - bdp->same_cmd_entry[cmd_type] = NULL; - } - -exit: - if (restart) { - mod_timer(&(bdp->nontx_timer_id), jiffies + 1); - } else { - if (netif_running(bdp->device)) - netif_wake_queue(bdp->device); - } - spin_unlock_bh(&(bdp->bd_non_tx_lock)); -} - -static void -e100_vlan_rx_register(struct net_device *netdev, struct vlan_group *grp) -{ - struct e100_private *bdp = netdev->priv; - - e100_disable_clear_intr(bdp); - bdp->vlgrp = grp; - - if(grp) { - /* enable VLAN tag insert/strip */ - e100_config_vlan_drop(bdp, true); - - } else { - /* disable VLAN tag insert/strip */ - e100_config_vlan_drop(bdp, false); - } - - e100_config(bdp); - e100_set_intr_mask(bdp); -} - -static void -e100_vlan_rx_add_vid(struct net_device *netdev, u16 vid) -{ - /* We don't do Vlan filtering */ - return; -} - -static void -e100_vlan_rx_kill_vid(struct net_device *netdev, u16 vid) -{ - struct e100_private *bdp = netdev->priv; - - if(bdp->vlgrp) - bdp->vlgrp->vlan_devices[vid] = NULL; - /* We don't do Vlan filtering */ - return; -} - -#ifdef CONFIG_PM -static int -e100_notify_reboot(struct notifier_block *nb, unsigned long event, void *p) -{ - struct pci_dev *pdev = NULL; - - switch(event) { - case SYS_DOWN: - case SYS_HALT: - case SYS_POWER_OFF: - while ((pdev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pdev)) != NULL) { - if(pci_dev_driver(pdev) == &e100_driver) { - /* If net_device struct is allocated? */ - if (pci_get_drvdata(pdev)) - e100_suspend(pdev, 3); - - } - } - } - return NOTIFY_DONE; -} - -static int -e100_suspend(struct pci_dev *pcid, u32 state) -{ - struct net_device *netdev = pci_get_drvdata(pcid); - struct e100_private *bdp = netdev->priv; - - e100_isolate_driver(bdp); - pci_save_state(pcid, bdp->pci_state); - - /* Enable or disable WoL */ - e100_do_wol(pcid, bdp); - - /* If wol is enabled */ - if (bdp->wolopts || e100_asf_enabled(bdp)) { - pci_enable_wake(pcid, 3, 1); /* Enable PME for power state D3 */ - pci_set_power_state(pcid, 3); /* Set power state to D3. */ - } else { - /* Disable bus mastering */ - pci_disable_device(pcid); - pci_set_power_state(pcid, state); - } - return 0; -} - -static int -e100_resume(struct pci_dev *pcid) -{ - struct net_device *netdev = pci_get_drvdata(pcid); - struct e100_private *bdp = netdev->priv; - - pci_set_power_state(pcid, 0); - pci_enable_wake(pcid, 0, 0); /* Clear PME status and disable PME */ - pci_restore_state(pcid, bdp->pci_state); - - /* Also do device full reset because device was in D3 state */ - e100_deisolate_driver(bdp, true); - - return 0; -} - -/** - * e100_asf_enabled - checks if ASF is configured on the current adaper - * by reading registers 0xD and 0x90 in the EEPROM - * @bdp: atapter's private data struct - * - * Returns: true if ASF is enabled - */ -static unsigned char -e100_asf_enabled(struct e100_private *bdp) -{ - u16 asf_reg; - u16 smbus_addr_reg; - if ((bdp->pdev->device >= 0x1050) && (bdp->pdev->device <= 0x1055)) { - asf_reg = e100_eeprom_read(bdp, EEPROM_CONFIG_ASF); - if ((asf_reg & EEPROM_FLAG_ASF) - && !(asf_reg & EEPROM_FLAG_GCL)) { - smbus_addr_reg = - e100_eeprom_read(bdp, EEPROM_SMBUS_ADDR); - if ((smbus_addr_reg & 0xFF) != 0xFE) - return true; - } - } - return false; -} -#endif /* CONFIG_PM */ - -#ifdef E100_CU_DEBUG -unsigned char -e100_cu_unknown_state(struct e100_private *bdp) -{ - u8 scb_cmd_low; - u16 scb_status; - scb_cmd_low = bdp->scb->scb_cmd_low; - scb_status = le16_to_cpu(bdp->scb->scb_status); - /* If CU is active and executing unknown cmd */ - if (scb_status & SCB_CUS_ACTIVE && scb_cmd_low & SCB_CUC_UNKNOWN) - return true; - else - return false; -} -#endif - diff -Nru a/drivers/net/e100/e100_phy.c b/drivers/net/e100/e100_phy.c --- a/drivers/net/e100/e100_phy.c Thu Jan 22 18:59:27 2004 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,1163 +0,0 @@ -/******************************************************************************* - - - Copyright(c) 1999 - 2003 Intel Corporation. All rights reserved. - - This program is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by the Free - Software Foundation; either version 2 of the License, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - this program; if not, write to the Free Software Foundation, Inc., 59 - Temple Place - Suite 330, Boston, MA 02111-1307, USA. - - The full GNU General Public License is included in this distribution in the - file called LICENSE. - - Contact Information: - Linux NICS - Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 -*******************************************************************************/ - -#include "e100_phy.h" - -void e100_handle_zlock(struct e100_private *bdp); - -/* - * Procedure: e100_mdi_write - * - * Description: This routine will write a value to the specified MII register - * of an external MDI compliant device (e.g. PHY 100). The - * command will execute in polled mode. - * - * Arguments: - * bdp - Ptr to this card's e100_bdconfig structure - * reg_addr - The MII register that we are writing to - * phy_addr - The MDI address of the Phy component. - * data - The value that we are writing to the MII register. - * - * Returns: - * NOTHING - */ -int -e100_mdi_write(struct e100_private *bdp, u32 reg_addr, u32 phy_addr, u16 data) -{ - int e100_retry; - u32 temp_val; - unsigned int mdi_cntrl; - - spin_lock_bh(&bdp->mdi_access_lock); - temp_val = (((u32) data) | (reg_addr << 16) | - (phy_addr << 21) | (MDI_WRITE << 26)); - writel(temp_val, &bdp->scb->scb_mdi_cntrl); - readw(&bdp->scb->scb_status); - - /* wait 20usec before checking status */ - udelay(20); - - /* poll for the mdi write to complete */ - e100_retry = E100_CMD_WAIT; - while ((!((mdi_cntrl = readl(&bdp->scb->scb_mdi_cntrl)) & MDI_PHY_READY)) && (e100_retry)) { - - udelay(20); - e100_retry--; - } - spin_unlock_bh(&bdp->mdi_access_lock); - if (mdi_cntrl & MDI_PHY_READY) - return 0; - else { - printk(KERN_ERR "e100: MDI write timeout\n"); - return 1; - } -} - -/* - * Procedure: e100_mdi_read - * - * Description: This routine will read a value from the specified MII register - * of an external MDI compliant device (e.g. PHY 100), and return - * it to the calling routine. The command will execute in polled - * mode. - * - * Arguments: - * bdp - Ptr to this card's e100_bdconfig structure - * reg_addr - The MII register that we are reading from - * phy_addr - The MDI address of the Phy component. - * - * Results: - * data - The value that we read from the MII register. - * - * Returns: - * NOTHING - */ -int -e100_mdi_read(struct e100_private *bdp, u32 reg_addr, u32 phy_addr, u16 *data) -{ - int e100_retry; - u32 temp_val; - unsigned int mdi_cntrl; - - spin_lock_bh(&bdp->mdi_access_lock); - /* Issue the read command to the MDI control register. */ - temp_val = ((reg_addr << 16) | (phy_addr << 21) | (MDI_READ << 26)); - writel(temp_val, &bdp->scb->scb_mdi_cntrl); - readw(&bdp->scb->scb_status); - - /* wait 20usec before checking status */ - udelay(20); - - /* poll for the mdi read to complete */ - e100_retry = E100_CMD_WAIT; - while ((!((mdi_cntrl = readl(&bdp->scb->scb_mdi_cntrl)) & MDI_PHY_READY)) && (e100_retry)) { - - udelay(20); - e100_retry--; - } - - spin_unlock_bh(&bdp->mdi_access_lock); - if (mdi_cntrl & MDI_PHY_READY) { - /* return the lower word */ - *data = (u16) mdi_cntrl; - return 0; - } - else { - printk(KERN_ERR "e100: MDI read timeout\n"); - return 1; - } -} - -static unsigned char -e100_phy_valid(struct e100_private *bdp, unsigned int phy_address) -{ - u16 ctrl_reg, stat_reg; - - /* Read the MDI control register */ - e100_mdi_read(bdp, MII_BMCR, phy_address, &ctrl_reg); - - /* Read the status register twice, bacause of sticky bits */ - e100_mdi_read(bdp, MII_BMSR, phy_address, &stat_reg); - e100_mdi_read(bdp, MII_BMSR, phy_address, &stat_reg); - - if ((ctrl_reg == 0xffff) || ((stat_reg == 0) && (ctrl_reg == 0))) - return false; - - return true; -} - -static void -e100_phy_address_detect(struct e100_private *bdp) -{ - unsigned int addr; - unsigned char valid_phy_found = false; - - if (IS_NC3133(bdp)) { - bdp->phy_addr = 0; - return; - } - - if (e100_phy_valid(bdp, PHY_DEFAULT_ADDRESS)) { - bdp->phy_addr = PHY_DEFAULT_ADDRESS; - valid_phy_found = true; - - } else { - for (addr = MIN_PHY_ADDR; addr <= MAX_PHY_ADDR; addr++) { - if (e100_phy_valid(bdp, addr)) { - bdp->phy_addr = addr; - valid_phy_found = true; - break; - } - } - } - - if (!valid_phy_found) { - bdp->phy_addr = PHY_ADDRESS_503; - } -} - -static void -e100_phy_id_detect(struct e100_private *bdp) -{ - u16 low_id_reg, high_id_reg; - - if (bdp->phy_addr == PHY_ADDRESS_503) { - bdp->PhyId = PHY_503; - return; - } - if (!(bdp->flags & IS_ICH)) { - if (bdp->rev_id >= D102_REV_ID) { - bdp->PhyId = PHY_82562ET; - return; - } - } - - /* Read phy id from the MII register */ - e100_mdi_read(bdp, MII_PHYSID1, bdp->phy_addr, &low_id_reg); - e100_mdi_read(bdp, MII_PHYSID2, bdp->phy_addr, &high_id_reg); - - bdp->PhyId = ((unsigned int) low_id_reg | - ((unsigned int) high_id_reg << 16)); -} - -static void -e100_phy_isolate(struct e100_private *bdp) -{ - unsigned int phy_address; - u16 ctrl_reg; - - /* Go over all phy addresses. Deisolate the selected one, and isolate - * all the rest */ - for (phy_address = 0; phy_address <= MAX_PHY_ADDR; phy_address++) { - if (phy_address != bdp->phy_addr) { - e100_mdi_write(bdp, MII_BMCR, phy_address, - BMCR_ISOLATE); - - } else { - e100_mdi_read(bdp, MII_BMCR, bdp->phy_addr, &ctrl_reg); - ctrl_reg &= ~BMCR_ISOLATE; - e100_mdi_write(bdp, MII_BMCR, bdp->phy_addr, ctrl_reg); - } - - udelay(100); - } -} - -static unsigned char -e100_phy_specific_setup(struct e100_private *bdp) -{ - u16 misc_reg; - - if (bdp->phy_addr == PHY_ADDRESS_503) { - switch (bdp->params.e100_speed_duplex) { - case E100_AUTONEG: - /* The adapter can't autoneg. so set to 10/HALF */ - printk(KERN_INFO - "e100: 503 serial component detected which " - "cannot autonegotiate\n"); - printk(KERN_INFO - "e100: speed/duplex forced to " - "10Mbps / Half duplex\n"); - bdp->params.e100_speed_duplex = E100_SPEED_10_HALF; - break; - - case E100_SPEED_100_HALF: - case E100_SPEED_100_FULL: - printk(KERN_ERR - "e100: 503 serial component detected " - "which does not support 100Mbps\n"); - printk(KERN_ERR - "e100: Change the forced speed/duplex " - "to a supported setting\n"); - return false; - } - - return true; - } - - if (IS_NC3133(bdp)) { - u16 int_reg; - - /* enable 100BASE fiber interface */ - e100_mdi_write(bdp, MDI_NC3133_CONFIG_REG, bdp->phy_addr, - MDI_NC3133_100FX_ENABLE); - - if ((bdp->params.e100_speed_duplex != E100_AUTONEG) && - (bdp->params.e100_speed_duplex != E100_SPEED_100_FULL)) { - /* just inform user about 100 full */ - printk(KERN_ERR "e100: NC3133 NIC can only run " - "at 100Mbps full duplex\n"); - } - - bdp->params.e100_speed_duplex = E100_SPEED_100_FULL; - - /* enable interrupts */ - e100_mdi_read(bdp, MDI_NC3133_INT_ENABLE_REG, - bdp->phy_addr, &int_reg); - int_reg |= MDI_NC3133_INT_ENABLE; - e100_mdi_write(bdp, MDI_NC3133_INT_ENABLE_REG, - bdp->phy_addr, int_reg); - } - - /* Handle the National TX */ - if ((bdp->PhyId & PHY_MODEL_REV_ID_MASK) == PHY_NSC_TX) { - e100_mdi_read(bdp, NSC_CONG_CONTROL_REG, - bdp->phy_addr, &misc_reg); - - misc_reg |= NSC_TX_CONG_TXREADY; - - /* disable the congestion control bit in the National Phy */ - misc_reg &= ~NSC_TX_CONG_ENABLE; - - e100_mdi_write(bdp, NSC_CONG_CONTROL_REG, - bdp->phy_addr, misc_reg); - } - - return true; -} - -/* - * Procedure: e100_phy_fix_squelch - * - * Description: - * Help find link on certain rare scenarios. - * NOTE: This routine must be called once per watchdog, - * and *after* setting the current link state. - * - * Arguments: - * bdp - Ptr to this card's e100_bdconfig structure - * - * Returns: - * NOTHING - */ -static void -e100_phy_fix_squelch(struct e100_private *bdp) -{ - if ((bdp->PhyId != PHY_82555_TX) || (bdp->flags & DF_SPEED_FORCED)) - return; - - if (netif_carrier_ok(bdp->device)) { - switch (bdp->PhyState) { - case 0: - break; - case 1: - e100_mdi_write(bdp, PHY_82555_SPECIAL_CONTROL, - bdp->phy_addr, 0x0000); - break; - case 2: - e100_mdi_write(bdp, PHY_82555_MDI_EQUALIZER_CSR, - bdp->phy_addr, 0x3000); - break; - } - bdp->PhyState = 0; - bdp->PhyDelay = 0; - - } else if (!bdp->PhyDelay--) { - switch (bdp->PhyState) { - case 0: - e100_mdi_write(bdp, PHY_82555_SPECIAL_CONTROL, - bdp->phy_addr, EXTENDED_SQUELCH_BIT); - bdp->PhyState = 1; - break; - case 1: - e100_mdi_write(bdp, PHY_82555_SPECIAL_CONTROL, - bdp->phy_addr, 0x0000); - e100_mdi_write(bdp, PHY_82555_MDI_EQUALIZER_CSR, - bdp->phy_addr, 0x2010); - bdp->PhyState = 2; - break; - case 2: - e100_mdi_write(bdp, PHY_82555_MDI_EQUALIZER_CSR, - bdp->phy_addr, 0x3000); - bdp->PhyState = 0; - break; - } - - e100_mdi_write(bdp, MII_BMCR, bdp->phy_addr, - BMCR_ANENABLE | BMCR_ANRESTART); - bdp->PhyDelay = 3; - } -} - -/* - * Procedure: e100_fix_polarity - * - * Description: - * Fix for 82555 auto-polarity toggle problem. With a short cable - * connecting an 82555 with an 840A link partner, if the medium is noisy, - * the 82555 sometime thinks that the polarity might be wrong and so - * toggles polarity. This happens repeatedly and results in a high bit - * error rate. - * NOTE: This happens only at 10 Mbps - * - * Arguments: - * bdp - Ptr to this card's e100_bdconfig structure - * - * Returns: - * NOTHING - */ -static void -e100_fix_polarity(struct e100_private *bdp) -{ - u16 status; - u16 errors; - u16 misc_reg; - int speed; - - if ((bdp->PhyId != PHY_82555_TX) && (bdp->PhyId != PHY_82562ET) && - (bdp->PhyId != PHY_82562EM)) - return; - - /* If the user wants auto-polarity disabled, do only that and nothing * - * else. * e100_autopolarity == 0 means disable --- we do just the - * disabling * e100_autopolarity == 1 means enable --- we do nothing at - * all * e100_autopolarity >= 2 means we do the workaround code. */ - /* Change for 82558 enhancement */ - switch (E100_AUTOPOLARITY) { - case 0: - e100_mdi_read(bdp, PHY_82555_SPECIAL_CONTROL, - bdp->phy_addr, &misc_reg); - e100_mdi_write(bdp, PHY_82555_SPECIAL_CONTROL, bdp->phy_addr, - (u16) (misc_reg | DISABLE_AUTO_POLARITY)); - break; - - case 1: - e100_mdi_read(bdp, PHY_82555_SPECIAL_CONTROL, - bdp->phy_addr, &misc_reg); - e100_mdi_write(bdp, PHY_82555_SPECIAL_CONTROL, bdp->phy_addr, - (u16) (misc_reg & ~DISABLE_AUTO_POLARITY)); - break; - - case 2: - /* we do this only if link is up */ - if (!netif_carrier_ok(bdp->device)) { - break; - } - - e100_mdi_read(bdp, PHY_82555_CSR, bdp->phy_addr, &status); - speed = (status & PHY_82555_SPEED_BIT) ? 100 : 10; - - /* we need to do this only if speed is 10 */ - if (speed != 10) { - break; - } - - /* see if we have any end of frame errors */ - e100_mdi_read(bdp, PHY_82555_EOF_COUNTER, - bdp->phy_addr, &errors); - - /* if non-zero, wait for 100 ms before reading again */ - if (errors) { - udelay(200); - e100_mdi_read(bdp, PHY_82555_EOF_COUNTER, - bdp->phy_addr, &errors); - - /* if non-zero again, we disable polarity */ - if (errors) { - e100_mdi_read(bdp, PHY_82555_SPECIAL_CONTROL, - bdp->phy_addr, &misc_reg); - e100_mdi_write(bdp, PHY_82555_SPECIAL_CONTROL, - bdp->phy_addr, - (u16) (misc_reg | - DISABLE_AUTO_POLARITY)); - } - } - - if (!errors) { - /* it is safe to read the polarity now */ - e100_mdi_read(bdp, PHY_82555_CSR, - bdp->phy_addr, &status); - - /* if polarity is normal, disable polarity */ - if (!(status & PHY_82555_POLARITY_BIT)) { - e100_mdi_read(bdp, PHY_82555_SPECIAL_CONTROL, - bdp->phy_addr, &misc_reg); - e100_mdi_write(bdp, PHY_82555_SPECIAL_CONTROL, - bdp->phy_addr, - (u16) (misc_reg | - DISABLE_AUTO_POLARITY)); - } - } - break; - - default: - break; - } -} - -/* - * Procedure: e100_find_speed_duplex - * - * Description: This routine will figure out what line speed and duplex mode - * the PHY is currently using. - * - * Arguments: - * bdp - Ptr to this card's e100_bdconfig structure - * - * Returns: - * NOTHING - */ -static void -e100_find_speed_duplex(struct e100_private *bdp) -{ - unsigned int PhyId; - u16 stat_reg, misc_reg; - u16 ad_reg, lp_ad_reg; - - PhyId = bdp->PhyId & PHY_MODEL_REV_ID_MASK; - - /* First we should check to see if we have link */ - /* If we don't have a link no reason to print a speed and duplex */ - if (!e100_update_link_state(bdp)) { - bdp->cur_line_speed = 0; - bdp->cur_dplx_mode = 0; - return; - } - - /* On the 82559 and later controllers, speed/duplex is part of the * - * SCB. So, we save an mdi_read and get these from the SCB. * */ - if (bdp->rev_id >= D101MA_REV_ID) { - /* Read speed */ - if (readb(&bdp->scb->scb_ext.d101m_scb.scb_gen_stat) & BIT_1) - bdp->cur_line_speed = 100; - else - bdp->cur_line_speed = 10; - - /* Read duplex */ - if (readb(&bdp->scb->scb_ext.d101m_scb.scb_gen_stat) & BIT_2) - bdp->cur_dplx_mode = FULL_DUPLEX; - else - bdp->cur_dplx_mode = HALF_DUPLEX; - - return; - } - - /* If this is a Phy 100, then read bits 1 and 0 of extended register 0, - * to get the current speed and duplex settings. */ - if ((PhyId == PHY_100_A) || (PhyId == PHY_100_C) || - (PhyId == PHY_82555_TX)) { - - /* Read Phy 100 extended register 0 */ - e100_mdi_read(bdp, EXTENDED_REG_0, bdp->phy_addr, &misc_reg); - - /* Get current speed setting */ - if (misc_reg & PHY_100_ER0_SPEED_INDIC) - bdp->cur_line_speed = 100; - else - bdp->cur_line_speed = 10; - - /* Get current duplex setting -- FDX enabled if bit is set */ - if (misc_reg & PHY_100_ER0_FDX_INDIC) - bdp->cur_dplx_mode = FULL_DUPLEX; - else - bdp->cur_dplx_mode = HALF_DUPLEX; - - return; - } - - /* See if link partner is capable of Auto-Negotiation (bit 0, reg 6) */ - e100_mdi_read(bdp, MII_EXPANSION, bdp->phy_addr, &misc_reg); - - /* See if Auto-Negotiation was complete (bit 5, reg 1) */ - e100_mdi_read(bdp, MII_BMSR, bdp->phy_addr, &stat_reg); - - /* If a True NWAY connection was made, then we can detect speed/dplx - * by ANDing our adapter's advertised abilities with our link partner's - * advertised ablilities, and then assuming that the highest common - * denominator was chosed by NWAY. */ - if ((misc_reg & EXPANSION_NWAY) && (stat_reg & BMSR_ANEGCOMPLETE)) { - - /* Read our advertisement register */ - e100_mdi_read(bdp, MII_ADVERTISE, bdp->phy_addr, &ad_reg); - - /* Read our link partner's advertisement register */ - e100_mdi_read(bdp, MII_LPA, bdp->phy_addr, &lp_ad_reg); - - /* AND the two advertisement registers together, and get rid - * of any extraneous bits. */ - ad_reg &= (lp_ad_reg & NWAY_LP_ABILITY); - - /* Get speed setting */ - if (ad_reg & - (ADVERTISE_100HALF | ADVERTISE_100FULL | - ADVERTISE_100BASE4)) - - bdp->cur_line_speed = 100; - else - bdp->cur_line_speed = 10; - - /* Get duplex setting -- use priority resolution algorithm */ - if (ad_reg & ADVERTISE_100BASE4) { - bdp->cur_dplx_mode = HALF_DUPLEX; - } else if (ad_reg & ADVERTISE_100FULL) { - bdp->cur_dplx_mode = FULL_DUPLEX; - } else if (ad_reg & ADVERTISE_100HALF) { - bdp->cur_dplx_mode = HALF_DUPLEX; - } else if (ad_reg & ADVERTISE_10FULL) { - bdp->cur_dplx_mode = FULL_DUPLEX; - } else { - bdp->cur_dplx_mode = HALF_DUPLEX; - } - - return; - } - - /* If we are connected to a dumb (non-NWAY) repeater or hub, and the - * line speed was determined automatically by parallel detection, then - * we have no way of knowing exactly what speed the PHY is set to - * unless that PHY has a propietary register which indicates speed in - * this situation. The NSC TX PHY does have such a register. Also, - * since NWAY didn't establish the connection, the duplex setting - * should HALF duplex. */ - bdp->cur_dplx_mode = HALF_DUPLEX; - - if (PhyId == PHY_NSC_TX) { - /* Read register 25 to get the SPEED_10 bit */ - e100_mdi_read(bdp, NSC_SPEED_IND_REG, bdp->phy_addr, &misc_reg); - - /* If bit 6 was set then we're at 10Mbps */ - if (misc_reg & NSC_TX_SPD_INDC_SPEED) - bdp->cur_line_speed = 10; - else - bdp->cur_line_speed = 100; - - } else { - /* If we don't know the line speed, default to 10Mbps */ - bdp->cur_line_speed = 10; - } -} - -/* - * Procedure: e100_force_speed_duplex - * - * Description: This routine forces line speed and duplex mode of the - * adapter based on the values the user has set in e100.c. - * - * Arguments: bdp - Pointer to the e100_private structure for the board - * - * Returns: void - * - */ -void -e100_force_speed_duplex(struct e100_private *bdp) -{ - u16 control; - unsigned long expires; - - bdp->flags |= DF_SPEED_FORCED; - - e100_mdi_read(bdp, MII_BMCR, bdp->phy_addr, &control); - control &= ~BMCR_ANENABLE; - control &= ~BMCR_LOOPBACK; - - switch (bdp->params.e100_speed_duplex) { - case E100_SPEED_10_HALF: - control &= ~BMCR_SPEED100; - control &= ~BMCR_FULLDPLX; - bdp->cur_line_speed = 10; - bdp->cur_dplx_mode = HALF_DUPLEX; - break; - - case E100_SPEED_10_FULL: - control &= ~BMCR_SPEED100; - control |= BMCR_FULLDPLX; - bdp->cur_line_speed = 10; - bdp->cur_dplx_mode = FULL_DUPLEX; - break; - - case E100_SPEED_100_HALF: - control |= BMCR_SPEED100; - control &= ~BMCR_FULLDPLX; - bdp->cur_line_speed = 100; - bdp->cur_dplx_mode = HALF_DUPLEX; - break; - - case E100_SPEED_100_FULL: - control |= BMCR_SPEED100; - control |= BMCR_FULLDPLX; - bdp->cur_line_speed = 100; - bdp->cur_dplx_mode = FULL_DUPLEX; - break; - } - - e100_mdi_write(bdp, MII_BMCR, bdp->phy_addr, control); - - /* loop must run at least once */ - expires = jiffies + 2 * HZ; - do { - if (e100_update_link_state(bdp) || - time_after(jiffies, expires)) { - break; - } else { - yield(); - } - - } while (true); -} - -void -e100_force_speed_duplex_to_phy(struct e100_private *bdp) -{ - u16 control; - - e100_mdi_read(bdp, MII_BMCR, bdp->phy_addr, &control); - control &= ~BMCR_ANENABLE; - control &= ~BMCR_LOOPBACK; - - switch (bdp->params.e100_speed_duplex) { - case E100_SPEED_10_HALF: - control &= ~BMCR_SPEED100; - control &= ~BMCR_FULLDPLX; - break; - - case E100_SPEED_10_FULL: - control &= ~BMCR_SPEED100; - control |= BMCR_FULLDPLX; - break; - - case E100_SPEED_100_HALF: - control |= BMCR_SPEED100; - control &= ~BMCR_FULLDPLX; - break; - - case E100_SPEED_100_FULL: - control |= BMCR_SPEED100; - control |= BMCR_FULLDPLX; - break; - } - - /* Send speed/duplex command to PHY layer. */ - e100_mdi_write(bdp, MII_BMCR, bdp->phy_addr, control); -} - -/* - * Procedure: e100_set_fc - * - * Description: Checks the link's capability for flow control. - * - * Arguments: bdp - Pointer to the e100_private structure for the board - * - * Returns: void - * - */ -static void -e100_set_fc(struct e100_private *bdp) -{ - u16 ad_reg; - u16 lp_ad_reg; - u16 exp_reg; - - /* no flow control for 82557, forced links or half duplex */ - if (!netif_carrier_ok(bdp->device) || (bdp->flags & DF_SPEED_FORCED) || - (bdp->cur_dplx_mode == HALF_DUPLEX) || - !(bdp->flags & IS_BACHELOR)) { - - bdp->flags &= ~DF_LINK_FC_CAP; - return; - } - - /* See if link partner is capable of Auto-Negotiation (bit 0, reg 6) */ - e100_mdi_read(bdp, MII_EXPANSION, bdp->phy_addr, &exp_reg); - - if (exp_reg & EXPANSION_NWAY) { - /* Read our advertisement register */ - e100_mdi_read(bdp, MII_ADVERTISE, bdp->phy_addr, &ad_reg); - - /* Read our link partner's advertisement register */ - e100_mdi_read(bdp, MII_LPA, bdp->phy_addr, &lp_ad_reg); - - ad_reg &= lp_ad_reg; /* AND the 2 ad registers */ - - if (ad_reg & NWAY_AD_FC_SUPPORTED) - bdp->flags |= DF_LINK_FC_CAP; - else - /* If link partner is capable of autoneg, but */ - /* not capable of flow control, Received PAUSE */ - /* frames are still honored, i.e., */ - /* transmitted frames would be paused */ - /* by incoming PAUSE frames */ - bdp->flags |= DF_LINK_FC_TX_ONLY; - - } else { - bdp->flags &= ~DF_LINK_FC_CAP; - } -} - -/* - * Procedure: e100_phy_check - * - * Arguments: bdp - Pointer to the e100_private structure for the board - * - * Returns: true if link state was changed - * false otherwise - * - */ -unsigned char -e100_phy_check(struct e100_private *bdp) -{ - unsigned char old_link; - unsigned char changed = false; - - old_link = netif_carrier_ok(bdp->device) ? 1 : 0; - e100_find_speed_duplex(bdp); - - if (!old_link && netif_carrier_ok(bdp->device)) { - e100_set_fc(bdp); - changed = true; - } - - if (old_link && !netif_carrier_ok(bdp->device)) { - /* reset the zero lock state */ - bdp->zlock_state = ZLOCK_INITIAL; - - // set auto lock for phy auto-negotiation on link up - if ((bdp->PhyId & PHY_MODEL_REV_ID_MASK) == PHY_82555_TX) - e100_mdi_write(bdp, PHY_82555_MDI_EQUALIZER_CSR, - bdp->phy_addr, 0); - changed = true; - } - - e100_phy_fix_squelch(bdp); - e100_handle_zlock(bdp); - - return changed; -} - -/* - * Procedure: e100_auto_neg - * - * Description: This routine will start autonegotiation and wait - * for it to complete - * - * Arguments: - * bdp - pointer to this card's e100_bdconfig structure - * force_restart - defines if autoneg should be restarted even if it - * has been completed before - * Returns: - * NOTHING - */ -static void -e100_auto_neg(struct e100_private *bdp, unsigned char force_restart) -{ - u16 stat_reg; - unsigned long expires; - - bdp->flags &= ~DF_SPEED_FORCED; - - e100_mdi_read(bdp, MII_BMSR, bdp->phy_addr, &stat_reg); - e100_mdi_read(bdp, MII_BMSR, bdp->phy_addr, &stat_reg); - - /* if we are capable of performing autoneg then we restart if needed */ - if ((stat_reg != 0xFFFF) && (stat_reg & BMSR_ANEGCAPABLE)) { - - if ((!force_restart) && - (stat_reg & BMSR_ANEGCOMPLETE)) { - goto exit; - } - - e100_mdi_write(bdp, MII_BMCR, bdp->phy_addr, - BMCR_ANENABLE | BMCR_ANRESTART); - - /* wait for autoneg to complete (up to 3 seconds) */ - expires = jiffies + HZ * 3; - do { - /* now re-read the value. Sticky so read twice */ - e100_mdi_read(bdp, MII_BMSR, bdp->phy_addr, &stat_reg); - e100_mdi_read(bdp, MII_BMSR, bdp->phy_addr, &stat_reg); - - if ((stat_reg & BMSR_ANEGCOMPLETE) || - time_after(jiffies, expires) ) { - goto exit; - } else { - yield(); - } - } while (true); - } - -exit: - e100_find_speed_duplex(bdp); -} - -void -e100_phy_set_speed_duplex(struct e100_private *bdp, unsigned char force_restart) -{ - if (bdp->params.e100_speed_duplex == E100_AUTONEG) { - if (bdp->rev_id >= D102_REV_ID) - /* Enable MDI/MDI-X auto switching */ - e100_mdi_write(bdp, MII_NCONFIG, bdp->phy_addr, - MDI_MDIX_AUTO_SWITCH_ENABLE); - e100_auto_neg(bdp, force_restart); - - } else { - if (bdp->rev_id >= D102_REV_ID) - /* Disable MDI/MDI-X auto switching */ - e100_mdi_write(bdp, MII_NCONFIG, bdp->phy_addr, - MDI_MDIX_RESET_ALL_MASK); - e100_force_speed_duplex(bdp); - } - - e100_set_fc(bdp); -} - -void -e100_phy_autoneg(struct e100_private *bdp) -{ - u16 ctrl_reg; - - ctrl_reg = BMCR_ANENABLE | BMCR_ANRESTART | BMCR_RESET; - - e100_mdi_write(bdp, MII_BMCR, bdp->phy_addr, ctrl_reg); - - udelay(100); -} - -void -e100_phy_set_loopback(struct e100_private *bdp) -{ - u16 ctrl_reg; - ctrl_reg = BMCR_LOOPBACK; - e100_mdi_write(bdp, MII_BMCR, bdp->phy_addr, ctrl_reg); - udelay(100); -} - -void -e100_phy_reset(struct e100_private *bdp) -{ - u16 ctrl_reg; - ctrl_reg = BMCR_RESET; - e100_mdi_write(bdp, MII_BMCR, bdp->phy_addr, ctrl_reg); - /* ieee 802.3 : The reset process shall be completed */ - /* within 0.5 seconds from the settting of PHY reset bit. */ - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(HZ / 2); -} - -unsigned char -e100_phy_init(struct e100_private *bdp) -{ - e100_phy_reset(bdp); - e100_phy_address_detect(bdp); - e100_phy_isolate(bdp); - e100_phy_id_detect(bdp); - - if (!e100_phy_specific_setup(bdp)) - return false; - - bdp->PhyState = 0; - bdp->PhyDelay = 0; - bdp->zlock_state = ZLOCK_INITIAL; - - e100_phy_set_speed_duplex(bdp, false); - e100_fix_polarity(bdp); - - return true; -} - -/* - * Procedure: e100_get_link_state - * - * Description: This routine checks the link status of the adapter - * - * Arguments: bdp - Pointer to the e100_private structure for the board - * - * - * Returns: true - If a link is found - * false - If there is no link - * - */ -unsigned char -e100_get_link_state(struct e100_private *bdp) -{ - unsigned char link = false; - u16 status; - - /* Check link status */ - /* If the controller is a 82559 or later one, link status is available - * from the CSR. This avoids the mdi_read. */ - if (bdp->rev_id >= D101MA_REV_ID) { - if (readb(&bdp->scb->scb_ext.d101m_scb.scb_gen_stat) & BIT_0) { - link = true; - } else { - link = false; - } - - } else { - /* Read the status register twice because of sticky bits */ - e100_mdi_read(bdp, MII_BMSR, bdp->phy_addr, &status); - e100_mdi_read(bdp, MII_BMSR, bdp->phy_addr, &status); - - if (status & BMSR_LSTATUS) { - link = true; - } else { - link = false; - } - } - - return link; -} - -/* - * Procedure: e100_update_link_state - * - * Description: This routine updates the link status of the adapter, - * also considering netif_running - * - * Arguments: bdp - Pointer to the e100_private structure for the board - * - * - * Returns: true - If a link is found - * false - If there is no link - * - */ -unsigned char -e100_update_link_state(struct e100_private *bdp) -{ - unsigned char link; - - /* Logical AND PHY link & netif_running */ - link = e100_get_link_state(bdp) && netif_running(bdp->device); - - if (link) { - if (!netif_carrier_ok(bdp->device)) - netif_carrier_on(bdp->device); - } else { - if (netif_carrier_ok(bdp->device)) - netif_carrier_off(bdp->device); - } - - return link; -} - -/**************************************************************************\ - ** - ** PROC NAME: e100_handle_zlock - ** This function manages a state machine that controls - ** the driver's zero locking algorithm. - ** This function is called by e100_watchdog() every ~2 second. - ** States: - ** The current link handling state is stored in - ** bdp->zlock_state, and is one of: - ** ZLOCK_INITIAL, ZLOCK_READING, ZLOCK_SLEEPING - ** Detailed description of the states and the transitions - ** between states is found below. - ** Note that any time the link is down / there is a reset - ** state will be changed outside this function to ZLOCK_INITIAL - ** Algorithm: - ** 1. If link is up & 100 Mbps continue else stay in #1: - ** 2. Set 'auto lock' - ** 3. Read & Store 100 times 'Zero' locked in 1 sec interval - ** 4. If max zero read >= 0xB continue else goto 1 - ** 5. Set most popular 'Zero' read in #3 - ** 6. Sleep 5 minutes - ** 7. Read number of errors, if it is > 300 goto 2 else goto 6 - ** Data Structures (in DRIVER_DATA): - ** zlock_state - current state of the algorithm - ** zlock_read_cnt - counts number of reads (up to 100) - ** zlock_read_data[i] - counts number of times 'Zero' read was i, 0 <= i <= 15 - ** zlock_sleep_cnt - keeps track of "sleep" time (up to 300 secs = 5 minutes) - ** - ** Parameters: DRIVER_DATA *bdp - ** - ** bdp - Pointer to HSM's adapter data space - ** - ** Return Value: NONE - ** - ** See Also: e100_watchdog() - ** - \**************************************************************************/ -void -e100_handle_zlock(struct e100_private *bdp) -{ - u16 pos; - u16 eq_reg; - u16 err_cnt; - u8 mpz; /* Most Popular Zero */ - - switch (bdp->zlock_state) { - case ZLOCK_INITIAL: - - if (((u8) bdp->rev_id <= D102_REV_ID) || - !(bdp->cur_line_speed == 100) || - !netif_carrier_ok(bdp->device)) { - break; - } - - /* initialize hw and sw and start reading */ - e100_mdi_write(bdp, PHY_82555_MDI_EQUALIZER_CSR, - bdp->phy_addr, 0); - /* reset read counters: */ - bdp->zlock_read_cnt = 0; - for (pos = 0; pos < 16; pos++) - bdp->zlock_read_data[pos] = 0; - /* start reading in the next call back: */ - bdp->zlock_state = ZLOCK_READING; - - /* FALL THROUGH !! */ - - case ZLOCK_READING: - /* state: reading (100 times) zero locked in 1 sec interval - * prev states: ZLOCK_INITIAL - * next states: ZLOCK_INITIAL, ZLOCK_SLEEPING */ - - e100_mdi_read(bdp, PHY_82555_MDI_EQUALIZER_CSR, - bdp->phy_addr, &eq_reg); - pos = (eq_reg & ZLOCK_ZERO_MASK) >> 4; - bdp->zlock_read_data[pos]++; - bdp->zlock_read_cnt++; - - if (bdp->zlock_read_cnt == ZLOCK_MAX_READS) { - /* check if we read a 'Zero' value of 0xB or greater */ - if ((bdp->zlock_read_data[0xB]) || - (bdp->zlock_read_data[0xC]) || - (bdp->zlock_read_data[0xD]) || - (bdp->zlock_read_data[0xE]) || - (bdp->zlock_read_data[0xF])) { - - /* we've read 'Zero' value of 0xB or greater, - * find most popular 'Zero' value and lock it */ - mpz = 0; - /* this loop finds the most popular 'Zero': */ - for (pos = 1; pos < 16; pos++) { - if (bdp->zlock_read_data[pos] > - bdp->zlock_read_data[mpz]) - - mpz = pos; - } - /* now lock the most popular 'Zero': */ - eq_reg = (ZLOCK_SET_ZERO | mpz); - e100_mdi_write(bdp, - PHY_82555_MDI_EQUALIZER_CSR, - bdp->phy_addr, eq_reg); - - /* sleep for 5 minutes: */ - bdp->zlock_sleep_cnt = jiffies; - bdp->zlock_state = ZLOCK_SLEEPING; - /* we will be reading the # of errors after 5 - * minutes, so we need to reset the error - * counters - these registers are self clearing - * on read, so read them */ - e100_mdi_read(bdp, PHY_82555_SYMBOL_ERR, - bdp->phy_addr, &err_cnt); - - } else { - /* we did not read a 'Zero' value of 0xB or - * above. go back to the start */ - bdp->zlock_state = ZLOCK_INITIAL; - } - - } - break; - - case ZLOCK_SLEEPING: - /* state: sleeping for 5 minutes - * prev states: ZLOCK_READING - * next states: ZLOCK_READING, ZLOCK_SLEEPING */ - - /* if 5 minutes have passed: */ - if ((jiffies - bdp->zlock_sleep_cnt) >= ZLOCK_MAX_SLEEP) { - /* read and sum up the number of errors: */ - e100_mdi_read(bdp, PHY_82555_SYMBOL_ERR, - bdp->phy_addr, &err_cnt); - /* if we've more than 300 errors (this number was - * calculated according to the spec max allowed errors - * (80 errors per 1 million frames) for 5 minutes in - * 100 Mbps (or the user specified max BER number) */ - if (err_cnt > bdp->params.ber) { - /* start again in the next callback: */ - bdp->zlock_state = ZLOCK_INITIAL; - } else { - /* we don't have more errors than allowed, - * sleep for 5 minutes */ - bdp->zlock_sleep_cnt = jiffies; - } - } - break; - - default: - break; - } -} diff -Nru a/drivers/net/e100/e100_phy.h b/drivers/net/e100/e100_phy.h --- a/drivers/net/e100/e100_phy.h Thu Jan 22 18:59:24 2004 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,158 +0,0 @@ -/******************************************************************************* - - - Copyright(c) 1999 - 2003 Intel Corporation. All rights reserved. - - This program is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by the Free - Software Foundation; either version 2 of the License, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - this program; if not, write to the Free Software Foundation, Inc., 59 - Temple Place - Suite 330, Boston, MA 02111-1307, USA. - - The full GNU General Public License is included in this distribution in the - file called LICENSE. - - Contact Information: - Linux NICS - Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 -*******************************************************************************/ - -#ifndef _E100_PHY_INC_ -#define _E100_PHY_INC_ - -#include "e100.h" - -/* - * Auto-polarity enable/disable - * e100_autopolarity = 0 => disable auto-polarity - * e100_autopolarity = 1 => enable auto-polarity - * e100_autopolarity = 2 => let software determine - */ -#define E100_AUTOPOLARITY 2 - -#define IS_NC3133(bdp) (((bdp)->pdev->subsystem_vendor == 0x0E11) && \ - ((bdp)->pdev->subsystem_device == 0xB0E1)) - -#define PHY_503 0 -#define PHY_100_A 0x000003E0 -#define PHY_100_C 0x035002A8 -#define PHY_NSC_TX 0x5c002000 -#define PHY_82562ET 0x033002A8 -#define PHY_82562EM 0x032002A8 -#define PHY_82562EH 0x017002A8 -#define PHY_82555_TX 0x015002a8 /* added this for 82555 */ -#define PHY_OTHER 0xFFFF -#define MAX_PHY_ADDR 31 -#define MIN_PHY_ADDR 0 - -#define PHY_MODEL_REV_ID_MASK 0xFFF0FFFF - -#define PHY_DEFAULT_ADDRESS 1 -#define PHY_ADDRESS_503 32 - -/* MDI Control register bit definitions */ -#define MDI_PHY_READY BIT_28 /* PHY is ready for next MDI cycle */ - -#define MDI_NC3133_CONFIG_REG 0x19 -#define MDI_NC3133_100FX_ENABLE BIT_2 -#define MDI_NC3133_INT_ENABLE_REG 0x17 -#define MDI_NC3133_INT_ENABLE BIT_1 - -/* MDI Control register opcode definitions */ -#define MDI_WRITE 1 /* Phy Write */ -#define MDI_READ 2 /* Phy read */ - -/* MDI register set*/ -#define AUTO_NEG_NEXT_PAGE_REG 0x07 /* Auto-negotiation next page xmit */ -#define EXTENDED_REG_0 0x10 /* Extended reg 0 (Phy 100 modes) */ -#define EXTENDED_REG_1 0x14 /* Extended reg 1 (Phy 100 error indications) */ -#define NSC_CONG_CONTROL_REG 0x17 /* National (TX) congestion control */ -#define NSC_SPEED_IND_REG 0x19 /* National (TX) speed indication */ - -#define HWI_CONTROL_REG 0x1D /* HWI Control register */ -/* MDI/MDI-X Control Register bit definitions */ -#define MDI_MDIX_RES_TIMER BIT_0_3 /* minimum slot time for resolution timer */ -#define MDI_MDIX_CONFIG_IS_OK BIT_4 /* 1 = resolution algorithm completes OK */ -#define MDI_MDIX_STATUS BIT_5 /* 1 = MDIX (croos over), 0 = MDI (straight through) */ -#define MDI_MDIX_SWITCH BIT_6 /* 1 = Forces to MDIX, 0 = Forces to MDI */ -#define MDI_MDIX_AUTO_SWITCH_ENABLE BIT_7 /* 1 = MDI/MDI-X feature enabled */ -#define MDI_MDIX_CONCT_CONFIG BIT_8 /* Sets the MDI/MDI-X connectivity configuration (test prupose only) */ -#define MDI_MDIX_CONCT_TEST_ENABLE BIT_9 /* 1 = Enables connectivity testing */ -#define MDI_MDIX_RESET_ALL_MASK 0x0000 - -/* HWI Control Register bit definitions */ -#define HWI_TEST_DISTANCE BIT_0_8 /* distance to cable problem */ -#define HWI_TEST_HIGHZ_PROBLEM BIT_9 /* 1 = Open Circuit */ -#define HWI_TEST_LOWZ_PROBLEM BIT_10 /* 1 = Short Circuit */ -#define HWI_TEST_RESERVED (BIT_11 | BIT_12) /* reserved */ -#define HWI_TEST_EXECUTE BIT_13 /* 1 = Execute the HWI test on the PHY */ -#define HWI_TEST_ABILITY BIT_14 /* 1 = test passed */ -#define HWI_TEST_ENABLE BIT_15 /* 1 = Enables the HWI feature */ -#define HWI_RESET_ALL_MASK 0x0000 - -/* ############Start of 82555 specific defines################## */ - -/* Intel 82555 specific registers */ -#define PHY_82555_CSR 0x10 /* 82555 CSR */ -#define PHY_82555_SPECIAL_CONTROL 0x11 /* 82555 special control register */ - -#define PHY_82555_RCV_ERR 0x15 /* 82555 100BaseTx Receive Error - * Frame Counter */ -#define PHY_82555_SYMBOL_ERR 0x16 /* 82555 RCV Symbol Error Counter */ -#define PHY_82555_PREM_EOF_ERR 0x17 /* 82555 100BaseTx RCV Premature End - * of Frame Error Counter */ -#define PHY_82555_EOF_COUNTER 0x18 /* 82555 end of frame error counter */ -#define PHY_82555_MDI_EQUALIZER_CSR 0x1a /* 82555 specific equalizer reg. */ - -/* 82555 CSR bits */ -#define PHY_82555_SPEED_BIT BIT_1 -#define PHY_82555_POLARITY_BIT BIT_8 - -/* 82555 equalizer reg. opcodes */ -#define ENABLE_ZERO_FORCING 0x2010 /* write to ASD conf. reg. 0 */ -#define DISABLE_ZERO_FORCING 0x2000 /* write to ASD conf. reg. 0 */ - -/* 82555 special control reg. opcodes */ -#define DISABLE_AUTO_POLARITY 0x0010 -#define EXTENDED_SQUELCH_BIT BIT_2 - -/* ############End of 82555 specific defines##################### */ - -/* Auto-Negotiation advertisement register bit definitions*/ -#define NWAY_AD_FC_SUPPORTED 0x0400 /* Flow Control supported */ - -/* Auto-Negotiation link partner ability register bit definitions*/ -#define NWAY_LP_ABILITY 0x07e0 /* technologies supported */ - -/* PHY 100 Extended Register 0 bit definitions*/ -#define PHY_100_ER0_FDX_INDIC BIT_0 /* 1 = FDX, 0 = half duplex */ -#define PHY_100_ER0_SPEED_INDIC BIT_1 /* 1 = 100Mbps, 0= 10Mbps */ - -/* National Semiconductor TX phy congestion control register bit definitions*/ -#define NSC_TX_CONG_TXREADY BIT_10 /* Makes TxReady an input */ -#define NSC_TX_CONG_ENABLE BIT_8 /* Enables congestion control */ - -/* National Semiconductor TX phy speed indication register bit definitions*/ -#define NSC_TX_SPD_INDC_SPEED BIT_6 /* 0 = 100Mbps, 1=10Mbps */ - -/************* function prototypes ************/ -extern unsigned char e100_phy_init(struct e100_private *bdp); -extern unsigned char e100_update_link_state(struct e100_private *bdp); -extern unsigned char e100_phy_check(struct e100_private *bdp); -extern void e100_phy_set_speed_duplex(struct e100_private *bdp, - unsigned char force_restart); -extern void e100_phy_autoneg(struct e100_private *bdp); -extern void e100_phy_reset(struct e100_private *bdp); -extern void e100_phy_set_loopback(struct e100_private *bdp); -extern int e100_mdi_write(struct e100_private *, u32, u32, u16); -extern int e100_mdi_read(struct e100_private *, u32, u32, u16 *); - -#endif diff -Nru a/drivers/net/e100/e100_test.c b/drivers/net/e100/e100_test.c --- a/drivers/net/e100/e100_test.c Thu Jan 22 18:59:25 2004 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,500 +0,0 @@ -/******************************************************************************* - - - Copyright(c) 1999 - 2003 Intel Corporation. All rights reserved. - - This program is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by the Free - Software Foundation; either version 2 of the License, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - this program; if not, write to the Free Software Foundation, Inc., 59 - Temple Place - Suite 330, Boston, MA 02111-1307, USA. - - The full GNU General Public License is included in this distribution in the - file called LICENSE. - - Contact Information: - Linux NICS - Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 -*******************************************************************************/ - -#include "e100_phy.h" -#include "e100_config.h" - -extern u16 e100_eeprom_read(struct e100_private *, u16); -extern int e100_wait_exec_cmplx(struct e100_private *, u32,u8, u8); -extern void e100_phy_reset(struct e100_private *bdp); -extern void e100_phy_autoneg(struct e100_private *bdp); -extern void e100_phy_set_loopback(struct e100_private *bdp); -extern void e100_force_speed_duplex(struct e100_private *bdp); - -static u8 e100_diag_selftest(struct net_device *); -static u8 e100_diag_eeprom(struct net_device *); -static u8 e100_diag_loopback(struct net_device *); - -static u8 e100_diag_one_loopback (struct net_device *, u8); -static u8 e100_diag_rcv_loopback_pkt(struct e100_private *); -static void e100_diag_config_loopback(struct e100_private *, u8, u8, u8 *,u8 *); -static u8 e100_diag_loopback_alloc(struct e100_private *); -static void e100_diag_loopback_cu_ru_exec(struct e100_private *); -static u8 e100_diag_check_pkt(u8 *); -static void e100_diag_loopback_free(struct e100_private *); -static int e100_cable_diag(struct e100_private *bdp); - -#define LB_PACKET_SIZE 1500 - -/** - * e100_run_diag - main test execution handler - checks mask of requests and calls the diag routines - * @dev: atapter's net device data struct - * @test_info: array with test request mask also used to store test results - * - * RETURNS: updated flags field of struct ethtool_test - */ -u32 -e100_run_diag(struct net_device *dev, u64 *test_info, u32 flags) -{ - struct e100_private* bdp = dev->priv; - u8 test_result = 0; - - if (!e100_get_link_state(bdp)) { - test_result = ETH_TEST_FL_FAILED; - test_info[test_link] = true; - } - if (!e100_diag_eeprom(dev)) { - test_result = ETH_TEST_FL_FAILED; - test_info[test_eeprom] = true; - } - if (flags & ETH_TEST_FL_OFFLINE) { - u8 fail_mask; - if (netif_running(dev)) { - spin_lock_bh(&dev->xmit_lock); - e100_close(dev); - spin_unlock_bh(&dev->xmit_lock); - } - if (e100_diag_selftest(dev)) { - test_result = ETH_TEST_FL_FAILED; - test_info[test_self_test] = true; - } - - fail_mask = e100_diag_loopback(dev); - if (fail_mask) { - test_result = ETH_TEST_FL_FAILED; - if (fail_mask & PHY_LOOPBACK) - test_info[test_loopback_phy] = true; - if (fail_mask & MAC_LOOPBACK) - test_info[test_loopback_mac] = true; - } - - test_info[cable_diag] = e100_cable_diag(bdp); - /* Need hw init regardless of netif_running */ - e100_hw_init(bdp); - if (netif_running(dev)) { - e100_open(dev); - } - } - else { - test_info[test_self_test] = false; - test_info[test_loopback_phy] = false; - test_info[test_loopback_mac] = false; - test_info[cable_diag] = false; - } - - return flags | test_result; -} - -/** - * e100_diag_selftest - run hardware selftest - * @dev: atapter's net device data struct - */ -static u8 -e100_diag_selftest(struct net_device *dev) -{ - struct e100_private *bdp = dev->priv; - u32 st_timeout, st_result; - u8 retval = 0; - - if (!e100_selftest(bdp, &st_timeout, &st_result)) { - if (!st_timeout) { - if (st_result & CB_SELFTEST_REGISTER_BIT) - retval |= REGISTER_TEST_FAIL; - if (st_result & CB_SELFTEST_DIAG_BIT) - retval |= SELF_TEST_FAIL; - if (st_result & CB_SELFTEST_ROM_BIT) - retval |= ROM_TEST_FAIL; - } else { - retval = TEST_TIMEOUT; - } - } - - return retval; -} - -/** - * e100_diag_eeprom - validate eeprom checksum correctness - * @dev: atapter's net device data struct - * - */ -static u8 -e100_diag_eeprom (struct net_device *dev) -{ - struct e100_private *bdp = dev->priv; - u16 i, eeprom_sum, eeprom_actual_csm; - - for (i = 0, eeprom_sum = 0; i < (bdp->eeprom_size - 1); i++) { - eeprom_sum += e100_eeprom_read(bdp, i); - } - - eeprom_actual_csm = e100_eeprom_read(bdp, bdp->eeprom_size - 1); - - if (eeprom_actual_csm == (u16)(EEPROM_SUM - eeprom_sum)) { - return true; - } - - return false; -} - -/** - * e100_diag_loopback - performs loopback test - * @dev: atapter's net device data struct - */ -static u8 -e100_diag_loopback (struct net_device *dev) -{ - u8 rc = 0; - - printk(KERN_DEBUG "%s: PHY loopback test starts\n", dev->name); - e100_hw_init(dev->priv); - if (!e100_diag_one_loopback(dev, PHY_LOOPBACK)) { - rc |= PHY_LOOPBACK; - } - printk(KERN_DEBUG "%s: PHY loopback test ends\n", dev->name); - - printk(KERN_DEBUG "%s: MAC loopback test starts\n", dev->name); - e100_hw_init(dev->priv); - if (!e100_diag_one_loopback(dev, MAC_LOOPBACK)) { - rc |= MAC_LOOPBACK; - } - printk(KERN_DEBUG "%s: MAC loopback test ends\n", dev->name); - - return rc; -} - -/** - * e100_diag_loopback - performs loopback test - * @dev: atapter's net device data struct - * @mode: lopback test type - */ -static u8 -e100_diag_one_loopback (struct net_device *dev, u8 mode) -{ - struct e100_private *bdp = dev->priv; - u8 res = false; - u8 saved_dynamic_tbd = false; - u8 saved_extended_tcb = false; - - if (!e100_diag_loopback_alloc(bdp)) - return false; - - /* change the config block to standard tcb and the correct loopback */ - e100_diag_config_loopback(bdp, true, mode, - &saved_extended_tcb, &saved_dynamic_tbd); - - e100_diag_loopback_cu_ru_exec(bdp); - - if (e100_diag_rcv_loopback_pkt(bdp)) { - res = true; - } - - e100_diag_loopback_free(bdp); - - /* change the config block to previous tcb mode and the no loopback */ - e100_diag_config_loopback(bdp, false, mode, - &saved_extended_tcb, &saved_dynamic_tbd); - return res; -} - -/** - * e100_diag_config_loopback - setup/clear loopback before/after lpbk test - * @bdp: atapter's private data struct - * @set_loopback: true if the function is called to set lb - * @loopback_mode: the loopback mode(MAC or PHY) - * @tcb_extended: true if need to set extended tcb mode after clean loopback - * @dynamic_tbd: true if needed to set dynamic tbd mode after clean loopback - * - */ -void -e100_diag_config_loopback(struct e100_private* bdp, - u8 set_loopback, - u8 loopback_mode, - u8* tcb_extended, - u8* dynamic_tbd) -{ - /* if set_loopback == true - we want to clear tcb_extended/dynamic_tbd. - * the previous values are saved in the params tcb_extended/dynamic_tbd - * if set_loopback == false - we want to restore previous value. - */ - if (set_loopback || (*tcb_extended)) - *tcb_extended = e100_config_tcb_ext_enable(bdp,*tcb_extended); - - if (set_loopback || (*dynamic_tbd)) - *dynamic_tbd = e100_config_dynamic_tbd(bdp,*dynamic_tbd); - - if (set_loopback) { - /* ICH PHY loopback is broken */ - if (bdp->flags & IS_ICH && loopback_mode == PHY_LOOPBACK) - loopback_mode = MAC_LOOPBACK; - /* Configure loopback on MAC */ - e100_config_loopback_mode(bdp,loopback_mode); - } else { - e100_config_loopback_mode(bdp,NO_LOOPBACK); - } - - e100_config(bdp); - - if (loopback_mode == PHY_LOOPBACK) { - if (set_loopback) - /* Set PHY loopback mode */ - e100_phy_set_loopback(bdp); - else - /* Reset PHY loopback mode */ - e100_phy_reset(bdp); - /* Wait for PHY state change */ - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(HZ); - } else { /* For MAC loopback wait 500 msec to take effect */ - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(HZ / 2); - } -} - -/** - * e100_diag_loopback_alloc - alloc & initate tcb and rfd for the loopback - * @bdp: atapter's private data struct - * - */ -static u8 -e100_diag_loopback_alloc(struct e100_private *bdp) -{ - dma_addr_t dma_handle; - tcb_t *tcb; - rfd_t *rfd; - tbd_t *tbd; - - /* tcb, tbd and transmit buffer are allocated */ - tcb = pci_alloc_consistent(bdp->pdev, - (sizeof (tcb_t) + sizeof (tbd_t) + - LB_PACKET_SIZE), - &dma_handle); - if (tcb == NULL) - return false; - - memset(tcb, 0x00, sizeof (tcb_t) + sizeof (tbd_t) + LB_PACKET_SIZE); - tcb->tcb_phys = dma_handle; - tcb->tcb_hdr.cb_status = 0; - tcb->tcb_hdr.cb_cmd = - cpu_to_le16(CB_EL_BIT | CB_TRANSMIT | CB_TX_SF_BIT); - /* Next command is null */ - tcb->tcb_hdr.cb_lnk_ptr = cpu_to_le32(0xffffffff); - tcb->tcb_cnt = 0; - tcb->tcb_thrshld = bdp->tx_thld; - tcb->tcb_tbd_num = 1; - /* Set up tcb tbd pointer */ - tcb->tcb_tbd_ptr = cpu_to_le32(tcb->tcb_phys + sizeof (tcb_t)); - tbd = (tbd_t *) ((u8 *) tcb + sizeof (tcb_t)); - /* Set up tbd transmit buffer */ - tbd->tbd_buf_addr = - cpu_to_le32(le32_to_cpu(tcb->tcb_tbd_ptr) + sizeof (tbd_t)); - tbd->tbd_buf_cnt = __constant_cpu_to_le16(1024); - /* The value of first 512 bytes is FF */ - memset((void *) ((u8 *) tbd + sizeof (tbd_t)), 0xFF, 512); - /* The value of second 512 bytes is BA */ - memset((void *) ((u8 *) tbd + sizeof (tbd_t) + 512), 0xBA, 512); - wmb(); - rfd = pci_alloc_consistent(bdp->pdev, sizeof (rfd_t), &dma_handle); - - if (rfd == NULL) { - pci_free_consistent(bdp->pdev, - sizeof (tcb_t) + sizeof (tbd_t) + - LB_PACKET_SIZE, tcb, tcb->tcb_phys); - return false; - } - - memset(rfd, 0x00, sizeof (rfd_t)); - - /* init all fields in rfd */ - rfd->rfd_header.cb_cmd = cpu_to_le16(RFD_EL_BIT); - rfd->rfd_sz = cpu_to_le16(ETH_FRAME_LEN + CHKSUM_SIZE); - /* dma_handle is physical address of rfd */ - bdp->loopback.dma_handle = dma_handle; - bdp->loopback.tcb = tcb; - bdp->loopback.rfd = rfd; - wmb(); - return true; -} - -/** - * e100_diag_loopback_cu_ru_exec - activates cu and ru to send & receive the pkt - * @bdp: atapter's private data struct - * - */ -static void -e100_diag_loopback_cu_ru_exec(struct e100_private *bdp) -{ - /*load CU & RU base */ - if(!e100_wait_exec_cmplx(bdp, bdp->loopback.dma_handle, SCB_RUC_START, 0)) - printk(KERN_ERR "e100: SCB_RUC_START failed!\n"); - - bdp->next_cu_cmd = START_WAIT; - e100_start_cu(bdp, bdp->loopback.tcb); - bdp->last_tcb = NULL; - rmb(); -} -/** - * e100_diag_check_pkt - checks if a given packet is a loopback packet - * @bdp: atapter's private data struct - * - * Returns true if OK false otherwise. - */ -static u8 -e100_diag_check_pkt(u8 *datap) -{ - int i; - for (i = 0; i<512; i++) { - if( !((*datap)==0xFF && (*(datap + 512) == 0xBA)) ) { - printk (KERN_ERR "e100: check loopback packet failed at: %x\n", i); - return false; - } - } - printk (KERN_DEBUG "e100: Check received loopback packet OK\n"); - return true; -} - -/** - * e100_diag_rcv_loopback_pkt - waits for receive and checks lpbk packet - * @bdp: atapter's private data struct - * - * Returns true if OK false otherwise. - */ -static u8 -e100_diag_rcv_loopback_pkt(struct e100_private* bdp) -{ - rfd_t *rfdp; - u16 rfd_status; - unsigned long expires = jiffies + HZ * 2; - - rfdp =bdp->loopback.rfd; - - rfd_status = le16_to_cpu(rfdp->rfd_header.cb_status); - - while (!(rfd_status & RFD_STATUS_COMPLETE)) { - if (time_before(jiffies, expires)) { - yield(); - rmb(); - rfd_status = le16_to_cpu(rfdp->rfd_header.cb_status); - } else { - break; - } - } - - if (rfd_status & RFD_STATUS_COMPLETE) { - printk(KERN_DEBUG "e100: Loopback packet received\n"); - return e100_diag_check_pkt(((u8 *)rfdp+bdp->rfd_size)); - } - else { - printk(KERN_ERR "e100: Loopback packet not received\n"); - return false; - } -} - -/** - * e100_diag_loopback_free - free data allocated for loopback pkt send/receive - * @bdp: atapter's private data struct - * - */ -static void -e100_diag_loopback_free (struct e100_private *bdp) -{ - pci_free_consistent(bdp->pdev, - sizeof(tcb_t) + sizeof(tbd_t) + LB_PACKET_SIZE, - bdp->loopback.tcb, bdp->loopback.tcb->tcb_phys); - - pci_free_consistent(bdp->pdev, sizeof(rfd_t), bdp->loopback.rfd, - bdp->loopback.dma_handle); -} - -static int -e100_cable_diag(struct e100_private *bdp) -{ - int saved_open_circut = 0xffff; - int saved_short_circut = 0xffff; - int saved_distance = 0xffff; - int saved_same = 0; - int cable_status = E100_CABLE_UNKNOWN; - int i; - - /* If we have link, */ - if (e100_get_link_state(bdp)) - return E100_CABLE_OK; - - if (bdp->rev_id < D102_REV_ID) - return E100_CABLE_UNKNOWN; - - /* Disable MDI/MDI-X auto switching */ - e100_mdi_write(bdp, MII_NCONFIG, bdp->phy_addr, - MDI_MDIX_RESET_ALL_MASK); - /* Set to 100 Full as required by cable test */ - e100_mdi_write(bdp, MII_BMCR, bdp->phy_addr, - BMCR_SPEED100 | BMCR_FULLDPLX); - - /* Test up to 100 times */ - for (i = 0; i < 100; i++) { - u16 ctrl_reg; - int distance, open_circut, short_circut, near_end; - - /* Enable and execute cable test */ - e100_mdi_write(bdp, HWI_CONTROL_REG, bdp->phy_addr, - (HWI_TEST_ENABLE | HWI_TEST_EXECUTE)); - /* Wait for cable test finished */ - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(HZ/100 + 1); - /* Read results */ - e100_mdi_read(bdp, HWI_CONTROL_REG, bdp->phy_addr, &ctrl_reg); - distance = ctrl_reg & HWI_TEST_DISTANCE; - open_circut = ctrl_reg & HWI_TEST_HIGHZ_PROBLEM; - short_circut = ctrl_reg & HWI_TEST_LOWZ_PROBLEM; - - if ((distance == saved_distance) && - (open_circut == saved_open_circut) && - (short_circut == saved_short_circut)) - saved_same++; - else { - saved_same = 0; - saved_distance = distance; - saved_open_circut = open_circut; - saved_short_circut = short_circut; - } - /* If results are the same 3 times */ - if (saved_same == 3) { - near_end = ((distance * HWI_REGISTER_GRANULARITY) < - HWI_NEAR_END_BOUNDARY); - if (open_circut) - cable_status = (near_end) ? - E100_CABLE_OPEN_NEAR : E100_CABLE_OPEN_FAR; - if (short_circut) - cable_status = (near_end) ? - E100_CABLE_SHORT_NEAR : E100_CABLE_SHORT_FAR; - break; - } - } - /* Reset cable test */ - e100_mdi_write(bdp, HWI_CONTROL_REG, bdp->phy_addr, HWI_RESET_ALL_MASK); - return cable_status; -} - diff -Nru a/drivers/net/e100/e100_ucode.h b/drivers/net/e100/e100_ucode.h --- a/drivers/net/e100/e100_ucode.h Thu Jan 22 18:59:26 2004 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,365 +0,0 @@ -/******************************************************************************* - - - Copyright(c) 1999 - 2003 Intel Corporation. All rights reserved. - - This program is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by the Free - Software Foundation; either version 2 of the License, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - this program; if not, write to the Free Software Foundation, Inc., 59 - Temple Place - Suite 330, Boston, MA 02111-1307, USA. - - The full GNU General Public License is included in this distribution in the - file called LICENSE. - - Contact Information: - Linux NICS - Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 -*******************************************************************************/ - -#ifndef _E100_UCODE_H_ -#define _E100_UCODE_H_ - -/* -e100_ucode.h - -This file contains the loadable micro code arrays to implement receive -bundling on the D101 A-step, D101 B-step, D101M (B-step only), D101S, -D102 B-step, D102 B-step with TCO work around and D102 C-step. - -Each controller has its own specific micro code array. The array for one -controller is totally incompatible with any other controller, and if used -will most likely cause the controller to lock up and stop responding to -the driver. Each micro code array has its own parameter offsets (described -below), and they each have their own version number. -*/ - -/************************************************************************* -* CPUSaver parameters -* -* All CPUSaver parameters are 16-bit literals that are part of a -* "move immediate value" instruction. By changing the value of -* the literal in the instruction before the code is loaded, the -* driver can change algorithm. -* -* CPUSAVER_DWORD - This is the location of the instruction that loads -* the dead-man timer with its inital value. By writing a 16-bit -* value to the low word of this instruction, the driver can change -* the timer value. The current default is either x600 or x800; -* experiments show that the value probably should stay within the -* range of x200 - x1000. -* -* CPUSAVER_BUNDLE_MAX_DWORD - This is the location of the instruction -* that sets the maximum number of frames that will be bundled. In -* some situations, such as the TCP windowing algorithm, it may be -* better to limit the growth of the bundle size than let it go as -* high as it can, because that could cause too much added latency. -* The default is six, because this is the number of packets in the -* default TCP window size. A value of 1 would make CPUSaver indicate -* an interrupt for every frame received. If you do not want to put -* a limit on the bundle size, set this value to xFFFF. -* -* CPUSAVER_MIN_SIZE_DWORD - This is the location of the instruction -* that contains a bit-mask describing the minimum size frame that -* will be bundled. The default masks the lower 7 bits, which means -* that any frame less than 128 bytes in length will not be bundled, -* but will instead immediately generate an interrupt. This does -* not affect the current bundle in any way. Any frame that is 128 -* bytes or large will be bundled normally. This feature is meant -* to provide immediate indication of ACK frames in a TCP environment. -* Customers were seeing poor performance when a machine with CPUSaver -* enabled was sending but not receiving. The delay introduced when -* the ACKs were received was enough to reduce total throughput, because -* the sender would sit idle until the ACK was finally seen. -* -* The current default is 0xFF80, which masks out the lower 7 bits. -* This means that any frame which is x7F (127) bytes or smaller -* will cause an immediate interrupt. Because this value must be a -* bit mask, there are only a few valid values that can be used. To -* turn this feature off, the driver can write the value xFFFF to the -* lower word of this instruction (in the same way that the other -* parameters are used). Likewise, a value of 0xF800 (2047) would -* cause an interrupt to be generated for every frame, because all -* standard Ethernet frames are <= 2047 bytes in length. -*************************************************************************/ - -#ifndef UCODE_MAX_DWORDS -#define UCODE_MAX_DWORDS 134 -#endif - -/********************************************************/ -/* CPUSaver micro code for the D101A */ -/********************************************************/ - -/* Version 2.0 */ - -/* This value is the same for both A and B step of 558. */ - -#define D101_CPUSAVER_TIMER_DWORD 72 -#define D101_CPUSAVER_BUNDLE_DWORD UCODE_MAX_DWORDS -#define D101_CPUSAVER_MIN_SIZE_DWORD UCODE_MAX_DWORDS - -#define D101_A_RCVBUNDLE_UCODE \ -{\ -0x03B301BB, 0x0046FFFF, 0xFFFFFFFF, 0x051DFFFF, 0xFFFFFFFF, 0xFFFFFFFF, \ -0x000C0001, 0x00101212, 0x000C0008, 0x003801BC, \ -0x00000000, 0x00124818, 0x000C1000, 0x00220809, \ -0x00010200, 0x00124818, 0x000CFFFC, 0x003803B5, \ -0x00000000, 0x00000000, 0x00000000, 0x00000000, \ -0x0010009C, 0x0024B81D, 0x00130836, 0x000C0001, \ -0x0026081C, 0x0020C81B, 0x00130824, 0x00222819, \ -0x00101213, 0x00041000, 0x003A03B3, 0x00010200, \ -0x00101B13, 0x00238081, 0x00213049, 0x0038003B, \ -0x00000000, 0x00000000, 0x00000000, 0x00000000, \ -0x00000000, 0x00000000, 0x00000000, 0x00000000, \ -0x00000000, 0x00000000, 0x00000000, 0x00000000, \ -0x00000000, 0x00000000, 0x00000000, 0x00000000, \ -0x0010009C, 0x0024B83E, 0x00130826, 0x000C0001, \ -0x0026083B, 0x00010200, 0x00134824, 0x000C0001, \ -0x00101213, 0x00041000, 0x0038051E, 0x00101313, \ -0x00010400, 0x00380521, 0x00050600, 0x00100824, \ -0x00101310, 0x00041000, 0x00080600, 0x00101B10, \ -0x0038051E, 0x00000000, 0x00000000, 0x00000000 \ -} - -/********************************************************/ -/* CPUSaver micro code for the D101B */ -/********************************************************/ - -/* Version 2.0 */ - -#define D101_B0_RCVBUNDLE_UCODE \ -{\ -0x03B401BC, 0x0047FFFF, 0xFFFFFFFF, 0x051EFFFF, 0xFFFFFFFF, 0xFFFFFFFF, \ -0x000C0001, 0x00101B92, 0x000C0008, 0x003801BD, \ -0x00000000, 0x00124818, 0x000C1000, 0x00220809, \ -0x00010200, 0x00124818, 0x000CFFFC, 0x003803B6, \ -0x00000000, 0x00000000, 0x00000000, 0x00000000, \ -0x0010009C, 0x0024B81D, 0x0013082F, 0x000C0001, \ -0x0026081C, 0x0020C81B, 0x00130837, 0x00222819, \ -0x00101B93, 0x00041000, 0x003A03B4, 0x00010200, \ -0x00101793, 0x00238082, 0x0021304A, 0x0038003C, \ -0x00000000, 0x00000000, 0x00000000, 0x00000000, \ -0x00000000, 0x00000000, 0x00000000, 0x00000000, \ -0x00000000, 0x00000000, 0x00000000, 0x00000000, \ -0x00000000, 0x00000000, 0x00000000, 0x00000000, \ -0x0010009C, 0x0024B83E, 0x00130826, 0x000C0001, \ -0x0026083B, 0x00010200, 0x00134837, 0x000C0001, \ -0x00101B93, 0x00041000, 0x0038051F, 0x00101313, \ -0x00010400, 0x00380522, 0x00050600, 0x00100837, \ -0x00101310, 0x00041000, 0x00080600, 0x00101790, \ -0x0038051F, 0x00000000, 0x00000000, 0x00000000 \ -} - -/********************************************************/ -/* CPUSaver micro code for the D101M (B-step only) */ -/********************************************************/ - -/* Version 2.10.1 */ - -/* Parameter values for the D101M B-step */ -#define D101M_CPUSAVER_TIMER_DWORD 78 -#define D101M_CPUSAVER_BUNDLE_DWORD 65 -#define D101M_CPUSAVER_MIN_SIZE_DWORD 126 - -#define D101M_B_RCVBUNDLE_UCODE \ -{\ -0x00550215, 0xFFFF0437, 0xFFFFFFFF, 0x06A70789, 0xFFFFFFFF, 0x0558FFFF, \ -0x000C0001, 0x00101312, 0x000C0008, 0x00380216, \ -0x0010009C, 0x00204056, 0x002380CC, 0x00380056, \ -0x0010009C, 0x00244C0B, 0x00000800, 0x00124818, \ -0x00380438, 0x00000000, 0x00140000, 0x00380555, \ -0x00308000, 0x00100662, 0x00100561, 0x000E0408, \ -0x00134861, 0x000C0002, 0x00103093, 0x00308000, \ -0x00100624, 0x00100561, 0x000E0408, 0x00100861, \ -0x000C007E, 0x00222C21, 0x000C0002, 0x00103093, \ -0x00380C7A, 0x00080000, 0x00103090, 0x00380C7A, \ -0x00000000, 0x00000000, 0x00000000, 0x00000000, \ -0x0010009C, 0x00244C2D, 0x00010004, 0x00041000, \ -0x003A0437, 0x00044010, 0x0038078A, 0x00000000, \ -0x00100099, 0x00206C7A, 0x0010009C, 0x00244C48, \ -0x00130824, 0x000C0001, 0x00101213, 0x00260C75, \ -0x00041000, 0x00010004, 0x00130826, 0x000C0006, \ -0x002206A8, 0x0013C926, 0x00101313, 0x003806A8, \ -0x00000000, 0x00000000, 0x00000000, 0x00000000, \ -0x00000000, 0x00000000, 0x00000000, 0x00000000, \ -0x00080600, 0x00101B10, 0x00050004, 0x00100826, \ -0x00101210, 0x00380C34, 0x00000000, 0x00000000, \ -0x0021155B, 0x00100099, 0x00206559, 0x0010009C, \ -0x00244559, 0x00130836, 0x000C0000, 0x00220C62, \ -0x000C0001, 0x00101B13, 0x00229C0E, 0x00210C0E, \ -0x00226C0E, 0x00216C0E, 0x0022FC0E, 0x00215C0E, \ -0x00214C0E, 0x00380555, 0x00010004, 0x00041000, \ -0x00278C67, 0x00040800, 0x00018100, 0x003A0437, \ -0x00130826, 0x000C0001, 0x00220559, 0x00101313, \ -0x00380559, 0x00000000, 0x00000000, 0x00000000, \ -0x00000000, 0x00000000, 0x00000000, 0x00000000, \ -0x00000000, 0x00130831, 0x0010090B, 0x00124813, \ -0x000CFF80, 0x002606AB, 0x00041000, 0x00010004, \ -0x003806A8, 0x00000000, 0x00000000, 0x00000000, \ -} - -/********************************************************/ -/* CPUSaver micro code for the D101S */ -/********************************************************/ - -/* Version 1.20.1 */ - -/* Parameter values for the D101S */ -#define D101S_CPUSAVER_TIMER_DWORD 78 -#define D101S_CPUSAVER_BUNDLE_DWORD 67 -#define D101S_CPUSAVER_MIN_SIZE_DWORD 128 - -#define D101S_RCVBUNDLE_UCODE \ -{\ -0x00550242, 0xFFFF047E, 0xFFFFFFFF, 0x06FF0818, 0xFFFFFFFF, 0x05A6FFFF, \ -0x000C0001, 0x00101312, 0x000C0008, 0x00380243, \ -0x0010009C, 0x00204056, 0x002380D0, 0x00380056, \ -0x0010009C, 0x00244F8B, 0x00000800, 0x00124818, \ -0x0038047F, 0x00000000, 0x00140000, 0x003805A3, \ -0x00308000, 0x00100610, 0x00100561, 0x000E0408, \ -0x00134861, 0x000C0002, 0x00103093, 0x00308000, \ -0x00100624, 0x00100561, 0x000E0408, 0x00100861, \ -0x000C007E, 0x00222FA1, 0x000C0002, 0x00103093, \ -0x00380F90, 0x00080000, 0x00103090, 0x00380F90, \ -0x00000000, 0x00000000, 0x00000000, 0x00000000, \ -0x0010009C, 0x00244FAD, 0x00010004, 0x00041000, \ -0x003A047E, 0x00044010, 0x00380819, 0x00000000, \ -0x00100099, 0x00206FFD, 0x0010009A, 0x0020AFFD, \ -0x0010009C, 0x00244FC8, 0x00130824, 0x000C0001, \ -0x00101213, 0x00260FF7, 0x00041000, 0x00010004, \ -0x00130826, 0x000C0006, 0x00220700, 0x0013C926, \ -0x00101313, 0x00380700, 0x00000000, 0x00000000, \ -0x00000000, 0x00000000, 0x00000000, 0x00000000, \ -0x00080600, 0x00101B10, 0x00050004, 0x00100826, \ -0x00101210, 0x00380FB6, 0x00000000, 0x00000000, \ -0x002115A9, 0x00100099, 0x002065A7, 0x0010009A, \ -0x0020A5A7, 0x0010009C, 0x002445A7, 0x00130836, \ -0x000C0000, 0x00220FE4, 0x000C0001, 0x00101B13, \ -0x00229F8E, 0x00210F8E, 0x00226F8E, 0x00216F8E, \ -0x0022FF8E, 0x00215F8E, 0x00214F8E, 0x003805A3, \ -0x00010004, 0x00041000, 0x00278FE9, 0x00040800, \ -0x00018100, 0x003A047E, 0x00130826, 0x000C0001, \ -0x002205A7, 0x00101313, 0x003805A7, 0x00000000, \ -0x00000000, 0x00000000, 0x00000000, 0x00000000, \ -0x00000000, 0x00000000, 0x00000000, 0x00130831, \ -0x0010090B, 0x00124813, 0x000CFF80, 0x00260703, \ -0x00041000, 0x00010004, 0x00380700 \ -} - -/********************************************************/ -/* CPUSaver micro code for the D102 B-step */ -/********************************************************/ - -/* Version 2.0 */ -/* Parameter values for the D102 B-step */ -#define D102_B_CPUSAVER_TIMER_DWORD 82 -#define D102_B_CPUSAVER_BUNDLE_DWORD 106 -#define D102_B_CPUSAVER_MIN_SIZE_DWORD 70 - -#define D102_B_RCVBUNDLE_UCODE \ -{\ -0x006F0276, 0x0EF71FFF, 0x0ED30F86, 0x0D250ED9, 0x1FFF1FFF, 0x1FFF04D2, \ -0x00300001, 0x0140D871, 0x00300008, 0x00E00277, \ -0x01406C57, 0x00816073, 0x008700FA, 0x00E00070, \ -0x00000000, 0x00000000, 0x00000000, 0x00000000, \ -0x00000000, 0x00000000, 0x00000000, 0x00000000, \ -0x01406CBA, 0x00807F9A, 0x00901F9A, 0x0024FFFF, \ -0x014B6F6F, 0x0030FFFE, 0x01407172, 0x01496FBA, \ -0x014B6F72, 0x00308000, 0x01406C52, 0x00912EFC, \ -0x00E00EF8, 0x00000000, 0x00000000, 0x00000000, \ -0x00906F8C, 0x00900F8C, 0x00E00F87, 0x00000000, \ -0x00906ED8, 0x01406C55, 0x00E00ED4, 0x00000000, \ -0x01406C51, 0x0080DFC2, 0x01406C52, 0x00815FC2, \ -0x01406C57, 0x00917FCC, 0x00E01FDD, 0x00000000, \ -0x00822D30, 0x01406C51, 0x0080CD26, 0x01406C52, \ -0x00814D26, 0x01406C57, 0x00916D26, 0x014C6FD7, \ -0x00300000, 0x00841FD2, 0x00300001, 0x0140D772, \ -0x00E012B3, 0x014C6F91, 0x0150710B, 0x01496F72, \ -0x0030FF80, 0x00940EDD, 0x00102000, 0x00038400, \ -0x00E00EDA, 0x00000000, 0x00000000, 0x00000000, \ -0x01406C57, 0x00917FE9, 0x00001000, 0x00E01FE9, \ -0x00200600, 0x0140D76F, 0x00138400, 0x01406FD8, \ -0x0140D96F, 0x00E01FDD, 0x00038400, 0x00102000, \ -0x00971FD7, 0x00101000, 0x00050200, 0x00E804D2, \ -0x014C6FD8, 0x00300001, 0x00840D26, 0x0140D872, \ -0x00E00D26, 0x014C6FD9, 0x00300001, 0x0140D972, \ -0x00941FBD, 0x00102000, 0x00038400, 0x014C6FD8, \ -0x00300006, 0x00840EDA, 0x014F71D8, 0x0140D872, \ -0x00E00EDA, 0x01496F50, 0x00E004D3, 0x00000000, \ -} - -/********************************************************/ -/* Micro code for the D102 C-step */ -/********************************************************/ - -/* Parameter values for the D102 C-step */ -#define D102_C_CPUSAVER_TIMER_DWORD 46 -#define D102_C_CPUSAVER_BUNDLE_DWORD 74 -#define D102_C_CPUSAVER_MIN_SIZE_DWORD 54 - -#define D102_C_RCVBUNDLE_UCODE \ -{ \ -0x00700279, 0x0E6604E2, 0x02BF0CAE, 0x1508150C, 0x15190E5B, 0x0E840F13, \ -0x00E014D8, 0x00000000, 0x00000000, 0x00000000, \ -0x00E014DC, 0x00000000, 0x00000000, 0x00000000, \ -0x00E014F4, 0x00000000, 0x00000000, 0x00000000, \ -0x00000000, 0x00000000, 0x00000000, 0x00000000, \ -0x00E014E0, 0x00000000, 0x00000000, 0x00000000, \ -0x00000000, 0x00000000, 0x00000000, 0x00000000, \ -0x00000000, 0x00000000, 0x00000000, 0x00000000, \ -0x00000000, 0x00000000, 0x00000000, 0x00000000, \ -0x00E014E7, 0x00000000, 0x00000000, 0x00000000, \ -0x00141000, 0x015D6F0D, 0x00E002C0, 0x00000000, \ -0x00200600, 0x00E0150D, 0x00000000, 0x00000000, \ -0x00000000, 0x00000000, 0x00000000, 0x00000000, \ -0x0030FF80, 0x00940E6A, 0x00038200, 0x00102000, \ -0x00E00E67, 0x00000000, 0x00000000, 0x00000000, \ -0x00000000, 0x00000000, 0x00000000, 0x00000000, \ -0x00000000, 0x00000000, 0x00000000, 0x00000000, \ -0x00906E65, 0x00800E60, 0x00E00E5D, 0x00000000, \ -0x00300006, 0x00E0151A, 0x00000000, 0x00000000, \ -0x00906F19, 0x00900F19, 0x00E00F14, 0x00000000, \ -0x00000000, 0x00000000, 0x00000000, 0x00000000, \ -0x01406CBA, 0x00807FDA, 0x00901FDA, 0x0024FFFF, \ -0x014B6F6F, 0x0030FFFE, 0x01407172, 0x01496FBA, \ -0x014B6F72, 0x00308000, 0x01406C52, 0x00912E89, \ -0x00E00E85, 0x00000000, 0x00000000, 0x00000000 \ -} - -/********************************************************/ -/* Micro code for the D102 E-step */ -/********************************************************/ - -/* Parameter values for the D102 E-step */ -#define D102_E_CPUSAVER_TIMER_DWORD 42 -#define D102_E_CPUSAVER_BUNDLE_DWORD 54 -#define D102_E_CPUSAVER_MIN_SIZE_DWORD 46 - -#define D102_E_RCVBUNDLE_UCODE \ -{\ -0x007D028F, 0x0E4204F9, 0x14ED0C85, 0x14FA14E9, 0x1FFF1FFF, 0x1FFF1FFF, \ -0x00E014B9, 0x00000000, 0x00000000, 0x00000000, \ -0x00E014BD, 0x00000000, 0x00000000, 0x00000000, \ -0x00E014D5, 0x00000000, 0x00000000, 0x00000000, \ -0x00000000, 0x00000000, 0x00000000, 0x00000000, \ -0x00E014C1, 0x00000000, 0x00000000, 0x00000000, \ -0x00000000, 0x00000000, 0x00000000, 0x00000000, \ -0x00000000, 0x00000000, 0x00000000, 0x00000000, \ -0x00000000, 0x00000000, 0x00000000, 0x00000000, \ -0x00E014C8, 0x00000000, 0x00000000, 0x00000000, \ -0x00200600, 0x00E014EE, 0x00000000, 0x00000000, \ -0x0030FF80, 0x00940E46, 0x00038200, 0x00102000, \ -0x00E00E43, 0x00000000, 0x00000000, 0x00000000, \ -0x00300006, 0x00E014FB, 0x00000000, 0x00000000 \ -} - -#endif /* _E100_UCODE_H_ */ diff -Nru a/drivers/net/e100.c b/drivers/net/e100.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/net/e100.c Thu Jan 22 18:59:27 2004 @@ -0,0 +1,2297 @@ +/******************************************************************************* + + + Copyright(c) 1999 - 2004 Intel Corporation. All rights reserved. + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., 59 + Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + The full GNU General Public License is included in this distribution in the + file called LICENSE. + + Contact Information: + Linux NICS + Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + +*******************************************************************************/ + +/* + * e100.c: Intel(R) PRO/100 ethernet driver + * + * (Re)written 2003 by scott.feldman@intel.com. Based loosely on + * original e100 driver, but better described as a munging of + * e100, e1000, eepro100, tg3, 8139cp, and other drivers. + * + * References: + * Intel 8255x 10/100 Mbps Ethernet Controller Family, + * Open Source Software Developers Manual, + * http://sourceforge.net/projects/e1000 + * + * + * Theory of Operation + * + * I. General + * + * The driver supports Intel(R) 10/100 Mbps PCI Fast Ethernet + * controller family, which includes the 82557, 82558, 82559, 82550, + * 82551, and 82562 devices. 82558 and greater controllers + * integrate the Intel 82555 PHY. The controllers are used in + * server and client network interface cards, as well as in + * LAN-On-Motherboard (LOM), CardBus, MiniPCI, and ICHx + * configurations. 8255x supports a 32-bit linear addressing + * mode and operates at 33Mhz PCI clock rate. + * + * II. Driver Operation + * + * Memory-mapped mode is used exclusively to access the device's + * shared-memory structure, the Control/Status Registers (CSR). All + * setup, configuration, and control of the device, including queuing + * of Tx, Rx, and configuration commands is through the CSR. + * cmd_lock serializes accesses to the CSR command register. cb_lock + * protects the shared Command Block List (CBL). + * + * 8255x is highly MII-compliant and all access to the PHY go + * through the Management Data Interface (MDI). Consequently, the + * driver leverages the mii.c library shared with other MII-compliant + * devices. + * + * Big- and Little-Endian byte order as well as 32- and 64-bit + * archs are supported. Weak-ordered memory and non-cache-coherent + * archs are supported. + * + * III. Transmit + * + * A Tx skb is mapped and hangs off of a TCB. TCBs are linked + * together in a fixed-size ring (CBL) thus forming the flexible mode + * memory structure. A TCB marked with the suspend-bit indicates + * the end of the ring. The last TCB processed suspends the + * controller, and the controller can be restarted by issue a CU + * resume command to continue from the suspend point, or a CU start + * command to start at a given position in the ring. + * + * Non-Tx commands (config, multicast setup, etc) are linked + * into the CBL ring along with Tx commands. The common structure + * used for both Tx and non-Tx commands is the Command Block (CB). + * + * cb_to_use is the next CB to use for queuing a command; cb_to_clean + * is the next CB to check for completion; cb_to_send is the first + * CB to start on in case of a previous failure to resume. CB clean + * up happens in interrupt context in response to a CU interrupt, or + * in dev->poll in the case where NAPI is enabled. cbs_avail keeps + * track of number of free CB resources available. + * + * Hardware padding of short packets to minimum packet size is + * enabled. 82557 pads with 7Eh, while the later controllers pad + * with 00h. + * + * IV. Recieve + * + * The Receive Frame Area (RFA) comprises a ring of Receive Frame + * Descriptors (RFD) + data buffer, thus forming the simplified mode + * memory structure. Rx skbs are allocated to contain both the RFD + * and the data buffer, but the RFD is pulled off before the skb is + * indicated. The data buffer is aligned such that encapsulated + * protocol headers are u32-aligned. Since the RFD is part of the + * mapped shared memory, and completion status is contained within + * the RFD, the RFD must be dma_sync'ed to maintain a consistent + * view from software and hardware. + * + * Under typical operation, the receive unit (RU) is start once, + * and the controller happily fills RFDs as frames arrive. If + * replacement RFDs cannot be allocated, or the RU goes non-active, + * the RU must be restarted. Frame arrival generates an interrupt, + * and Rx indication and re-allocation happen in the same context, + * therefore no locking is required. If NAPI is enabled, this work + * happens in dev->poll. A software-generated interrupt is gen- + * erated from the watchdog to recover from a failed allocation + * senario where all Rx resources have been indicated and none re- + * placed. + * + * V. Miscellaneous + * + * VLAN offloading of tagging, stripping and filtering is not + * supported, but driver will accommodate the extra 4-byte VLAN tag + * for processing by upper layers. Tx/Rx Checksum offloading is not + * supported. Tx Scatter/Gather is not supported. Jumbo Frames is + * not supported (hardware limitation). + * + * NAPI support is enabled with CONFIG_E100_NAPI. + * + * MagicPacket(tm) WoL support is enabled/disabled via ethtool. + * + * Thanks to JC (jchapman@katalix.com) for helping with + * testing/troubleshooting the development driver. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#define DRV_NAME "e100" +#define DRV_VERSION "3.0.13_dev" +#define DRV_DESCRIPTION "Intel(R) PRO/100 Network Driver" +#define DRV_COPYRIGHT "Copyright(c) 1999-2004 Intel Corporation" +#define PFX DRV_NAME ": " + +#define E100_WATCHDOG_PERIOD 2 * HZ +#define E100_NAPI_WEIGHT 16 + +MODULE_DESCRIPTION(DRV_DESCRIPTION); +MODULE_AUTHOR(DRV_COPYRIGHT); +MODULE_LICENSE("GPL"); + +static int debug = 3; +module_param(debug, int, 0); +MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all)"); +#define DPRINTK(nlevel, klevel, fmt, args...) \ + (void)((NETIF_MSG_##nlevel & nic->msg_enable) && \ + printk(KERN_##klevel PFX "%s: %s: " fmt, nic->netdev->name, \ + __FUNCTION__ , ## args)) + +#define INTEL_8255X_ETHERNET_DEVICE(device_id, ich) {\ + PCI_VENDOR_ID_INTEL, device_id, PCI_ANY_ID, PCI_ANY_ID, \ + PCI_CLASS_NETWORK_ETHERNET << 8, 0xFFFF00, ich } +static struct pci_device_id e100_id_table[] = { + INTEL_8255X_ETHERNET_DEVICE(0x1029, 0), + INTEL_8255X_ETHERNET_DEVICE(0x1030, 0), + INTEL_8255X_ETHERNET_DEVICE(0x1031, 3), + INTEL_8255X_ETHERNET_DEVICE(0x1032, 3), + INTEL_8255X_ETHERNET_DEVICE(0x1033, 3), + INTEL_8255X_ETHERNET_DEVICE(0x1034, 3), + INTEL_8255X_ETHERNET_DEVICE(0x1038, 3), + INTEL_8255X_ETHERNET_DEVICE(0x1039, 4), + INTEL_8255X_ETHERNET_DEVICE(0x103A, 4), + INTEL_8255X_ETHERNET_DEVICE(0x103B, 4), + INTEL_8255X_ETHERNET_DEVICE(0x103C, 4), + INTEL_8255X_ETHERNET_DEVICE(0x103D, 4), + INTEL_8255X_ETHERNET_DEVICE(0x103E, 4), + INTEL_8255X_ETHERNET_DEVICE(0x1050, 5), + INTEL_8255X_ETHERNET_DEVICE(0x1051, 5), + INTEL_8255X_ETHERNET_DEVICE(0x1052, 5), + INTEL_8255X_ETHERNET_DEVICE(0x1053, 5), + INTEL_8255X_ETHERNET_DEVICE(0x1054, 5), + INTEL_8255X_ETHERNET_DEVICE(0x1055, 5), + INTEL_8255X_ETHERNET_DEVICE(0x1064, 6), + INTEL_8255X_ETHERNET_DEVICE(0x1065, 6), + INTEL_8255X_ETHERNET_DEVICE(0x1066, 6), + INTEL_8255X_ETHERNET_DEVICE(0x1067, 6), + INTEL_8255X_ETHERNET_DEVICE(0x1068, 6), + INTEL_8255X_ETHERNET_DEVICE(0x1069, 6), + INTEL_8255X_ETHERNET_DEVICE(0x106A, 6), + INTEL_8255X_ETHERNET_DEVICE(0x106B, 6), + INTEL_8255X_ETHERNET_DEVICE(0x1059, 0), + INTEL_8255X_ETHERNET_DEVICE(0x1209, 0), + INTEL_8255X_ETHERNET_DEVICE(0x1229, 0), + INTEL_8255X_ETHERNET_DEVICE(0x2449, 2), + INTEL_8255X_ETHERNET_DEVICE(0x2459, 2), + INTEL_8255X_ETHERNET_DEVICE(0x245D, 2), + { 0, } +}; +MODULE_DEVICE_TABLE(pci, e100_id_table); + +enum mac { + mac_82557_D100_A = 0, + mac_82557_D100_B = 1, + mac_82557_D100_C = 2, + mac_82558_D101_A4 = 4, + mac_82558_D101_B0 = 5, + mac_82559_D101M = 8, + mac_82559_D101S = 9, + mac_82550_D102 = 12, + mac_82550_D102_C = 13, + mac_82551_E = 14, + mac_82551_F = 15, + mac_82551_10 = 16, + mac_unknown = 0xFF, +}; + +enum phy { + phy_100a = 0x000003E0, + phy_100c = 0x035002A8, + phy_82555_tx = 0x015002A8, + phy_nsc_tx = 0x5C002000, + phy_82562_et = 0x033002A8, + phy_82562_em = 0x032002A8, + phy_82562_eh = 0x017002A8, + phy_unknown = 0xFFFFFFFF, +}; + +/* CSR (Control/Status Registers) */ +struct csr { + struct { + u8 status; + u8 stat_ack; + u8 cmd_lo; + u8 cmd_hi; + u32 gen_ptr; + } scb; + u32 port; + u16 flash_ctrl; + u8 eeprom_ctrl_lo; + u8 eeprom_ctrl_hi; + u32 mdi_ctrl; + u32 rx_dma_count; +}; + +enum scb_status { + rus_ready = 0x10, + rus_mask = 0x3C, +}; + +enum scb_stat_ack { + stat_ack_not_ours = 0x00, + stat_ack_sw_gen = 0x04, + stat_ack_rnr = 0x10, + stat_ack_cu_idle = 0x20, + stat_ack_frame_rx = 0x40, + stat_ack_cu_cmd_done = 0x80, + stat_ack_not_present = 0xFF, + stat_ack_rx = (stat_ack_sw_gen | stat_ack_rnr | stat_ack_frame_rx), + stat_ack_tx = (stat_ack_cu_idle | stat_ack_cu_cmd_done), +}; + +enum scb_cmd_hi { + irq_mask_none = 0x00, + irq_mask_all = 0x01, + irq_sw_gen = 0x02, +}; + +enum scb_cmd_lo { + ruc_start = 0x01, + ruc_load_base = 0x06, + cuc_start = 0x10, + cuc_resume = 0x20, + cuc_dump_addr = 0x40, + cuc_dump_stats = 0x50, + cuc_load_base = 0x60, + cuc_dump_reset = 0x70, +}; + +enum port { + software_reset = 0x0000, + selftest = 0x0001, + selective_reset = 0x0002, +}; + +enum eeprom_ctrl_lo { + eesk = 0x01, + eecs = 0x02, + eedi = 0x04, + eedo = 0x08, +}; + +enum mdi_ctrl { + mdi_write = 0x04000000, + mdi_read = 0x08000000, + mdi_ready = 0x10000000, +}; + +enum eeprom_op { + op_write = 0x05, + op_read = 0x06, + op_ewds = 0x10, + op_ewen = 0x13, +}; + +enum eeprom_offsets { + eeprom_id = 0x0A, + eeprom_config_asf = 0x0D, + eeprom_smbus_addr = 0x90, +}; + +enum eeprom_id { + eeprom_id_wol = 0x0020, +}; + +enum eeprom_config_asf { + eeprom_asf = 0x8000, + eeprom_gcl = 0x4000, +}; + +enum cb_status { + cb_complete = 0x8000, + cb_ok = 0x2000, +}; + +enum cb_command { + cb_iaaddr = 0x0001, + cb_config = 0x0002, + cb_multi = 0x0003, + cb_tx = 0x0004, + cb_dump = 0x0006, + cb_tx_sf = 0x0008, + cb_cid = 0x1f00, + cb_i = 0x2000, + cb_s = 0x4000, + cb_el = 0x8000, +}; + +struct rfd { + u16 status; + u16 command; + u32 link; + u32 rbd; + u16 actual_size; + u16 size; +}; + +struct rx { + struct rx *next, *prev; + struct sk_buff *skb; + dma_addr_t dma_addr; +}; + +#if defined(__BIG_ENDIAN_BITFIELD) +#define X(a,b) b,a +#else +#define X(a,b) a,b +#endif +struct config { +/*0*/ u8 X(byte_count:6, pad0:2); +/*1*/ u8 X(X(rx_fifo_limit:4, tx_fifo_limit:3), pad1:1); +/*2*/ u8 adaptive_ifs; +/*3*/ u8 X(X(X(X(mwi_enable:1, type_enable:1), read_align_enable:1), + term_write_cache_line:1), pad3:4); +/*4*/ u8 X(rx_dma_max_count:7, pad4:1); +/*5*/ u8 X(tx_dma_max_count:7, dma_max_count_enable:1); +/*6*/ u8 X(X(X(X(X(X(X(late_scb_update:1, direct_rx_dma:1), + tno_intr:1), cna_intr:1), standard_tcb:1), standard_stat_counter:1), + rx_discard_overruns:1), rx_save_bad_frames:1); +/*7*/ u8 X(X(X(X(X(rx_discard_short_frames:1, tx_underrun_retry:2), + pad7:2), rx_extended_rfd:1), tx_two_frames_in_fifo:1), + tx_dynamic_tbd:1); +/*8*/ u8 X(X(mii_mode:1, pad8:6), csma_disabled:1); +/*9*/ u8 X(X(X(X(X(rx_tcpudp_checksum:1, pad9:3), vlan_arp_tco:1), + link_status_wake:1), arp_wake:1), mcmatch_wake:1); +/*10*/ u8 X(X(X(pad10:3, no_source_addr_insertion:1), preamble_length:2), + loopback:2); +/*11*/ u8 X(linear_priority:3, pad11:5); +/*12*/ u8 X(X(linear_priority_mode:1, pad12:3), ifs:4); +/*13*/ u8 ip_addr_lo; +/*14*/ u8 ip_addr_hi; +/*15*/ u8 X(X(X(X(X(X(X(promiscuous_mode:1, broadcast_disabled:1), + wait_after_win:1), pad15_1:1), ignore_ul_bit:1), crc_16_bit:1), + pad15_2:1), crs_or_cdt:1); +/*16*/ u8 fc_delay_lo; +/*17*/ u8 fc_delay_hi; +/*18*/ u8 X(X(X(X(X(rx_stripping:1, tx_padding:1), rx_crc_transfer:1), + rx_long_ok:1), fc_priority_threshold:3), pad18:1); +/*19*/ u8 X(X(X(X(X(X(X(addr_wake:1, magic_packet_disable:1), + fc_disable:1), fc_restop:1), fc_restart:1), fc_reject:1), + full_duplex_force:1), full_duplex_pin:1); +/*20*/ u8 X(X(X(pad20_1:5, fc_priority_location:1), multi_ia:1), pad20_2:1); +/*21*/ u8 X(X(pad21_1:3, multicast_all:1), pad21_2:4); +/*22*/ u8 X(X(rx_d102_mode:1, rx_vlan_drop:1), pad22:6); + u8 pad_d102[9]; +}; + +#define E100_MAX_MULTICAST_ADDRS 64 +struct multi { + u16 count; + u8 addr[E100_MAX_MULTICAST_ADDRS * ETH_ALEN + 2/*pad*/]; +}; + +/* Important: keep total struct u32-aligned */ +struct cb { + u16 status; + u16 command; + u32 link; + union { + u8 iaaddr[ETH_ALEN]; + struct config config; + struct multi multi; + struct { + u32 tbd_array; + u16 tcb_byte_count; + u8 threshold; + u8 tbd_count; + struct { + u32 buf_addr; + u16 size; + u16 eol; + } tbd; + } tcb; + u32 dump_buffer_addr; + } u; + struct cb *next, *prev; + dma_addr_t dma_addr; + struct sk_buff *skb; +}; + +enum loopback { + lb_none = 0, lb_mac = 1, lb_phy = 3, +}; + +struct stats { + u32 tx_good_frames, tx_max_collisions, tx_late_collisions, + tx_underruns, tx_lost_crs, tx_deferred, tx_single_collisions, + tx_multiple_collisions, tx_total_collisions; + u32 rx_good_frames, rx_crc_errors, rx_alignment_errors, + rx_resource_errors, rx_overrun_errors, rx_cdt_errors, + rx_short_frame_errors; + u32 fc_xmt_pause, fc_rcv_pause, fc_rcv_unsupported; + u16 xmt_tco_frames, rcv_tco_frames; + u32 complete; +}; + +struct mem { + struct { + u32 signature; + u32 result; + } selftest; + struct stats stats; + u8 dump_buf[596]; +}; + +struct param_range { + u32 min; + u32 max; + u32 count; +}; + +struct params { + struct param_range rfds; + struct param_range cbs; +}; + +struct nic { + /* Begin: frequently used values: keep adjacent for cache effect */ + u32 msg_enable ____cacheline_aligned; + struct net_device *netdev; + struct pci_dev *pdev; + + struct rx *rxs ____cacheline_aligned; + struct rx *rx_to_use; + struct rx *rx_to_clean; + struct rfd blank_rfd; + int ru_running; + + spinlock_t cb_lock ____cacheline_aligned; + spinlock_t cmd_lock; + struct csr *csr; + enum scb_cmd_lo cuc_cmd; + unsigned int cbs_avail; + struct cb *cbs; + struct cb *cb_to_use; + struct cb *cb_to_send; + struct cb *cb_to_clean; + u16 tx_command; + /* End: frequently used values: keep adjacent for cache effect */ + + enum { + ich = (1 << 0), + promiscuous = (1 << 1), + multicast_all = (1 << 2), + wol_magic = (1 << 3), + } flags ____cacheline_aligned; + + enum mac mac; + enum phy phy; + struct params params; + struct net_device_stats net_stats; + struct timer_list watchdog; + struct timer_list blink_timer; + struct mii_if_info mii; + enum loopback loopback; + + struct mem *mem; + dma_addr_t dma_addr; + + dma_addr_t cbs_dma_addr; + u8 adaptive_ifs; + u8 tx_threshold; + u32 tx_frames; + u32 tx_collisions; + u32 tx_deferred; + u32 tx_single_collisions; + u32 tx_multiple_collisions; + u32 tx_fc_pause; + u32 tx_tco_frames; + + u32 rx_fc_pause; + u32 rx_fc_unsupported; + u32 rx_tco_frames; + + u8 rev_id; + u16 leds; + u16 eeprom_wc; + u16 eeprom[256]; + u32 pm_state[16]; +}; + +static inline void e100_write_flush(struct nic *nic) +{ + /* Flush previous PCI writes through intermediate bridges + * by doing a benign read */ + (void)readb(&nic->csr->scb.status); +} + +static inline void e100_enable_irq(struct nic *nic) +{ + writeb(irq_mask_none, &nic->csr->scb.cmd_hi); + e100_write_flush(nic); +} + +static inline void e100_disable_irq(struct nic *nic) +{ + writeb(irq_mask_all, &nic->csr->scb.cmd_hi); + e100_write_flush(nic); +} + +static void e100_hw_reset(struct nic *nic) +{ + /* Put CU and RU into idle with a selective reset to get + * device off of PCI bus */ + writel(selective_reset, &nic->csr->port); + e100_write_flush(nic); udelay(20); + + /* Now fully reset device */ + writel(software_reset, &nic->csr->port); + e100_write_flush(nic); udelay(20); + + /* TCO workaround - 82559 and greater */ + if(nic->mac >= mac_82559_D101M) { + /* Issue a redundant CU load base without setting + * general pointer, and without waiting for scb to + * clear. This gets us into post-driver. Finally, + * wait 20 msec for reset to take effect. */ + writeb(cuc_load_base, &nic->csr->scb.cmd_lo); + mdelay(20); + } + + /* Mask off our interrupt line - it's unmasked after reset */ + e100_disable_irq(nic); +} + +static int e100_self_test(struct nic *nic) +{ + u32 dma_addr = nic->dma_addr + offsetof(struct mem, selftest); + + /* Passing the self-test is a pretty good indication + * that the device can DMA to/from host memory */ + + nic->mem->selftest.signature = 0; + nic->mem->selftest.result = 0xFFFFFFFF; + + writel(selftest | dma_addr, &nic->csr->port); + e100_write_flush(nic); + /* Wait 10 msec for self-test to complete */ + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(HZ / 100 + 1); + + /* Interrupts are enabled after self-test */ + e100_disable_irq(nic); + + /* Check results of self-test */ + if(nic->mem->selftest.result != 0) { + DPRINTK(HW, ERR, "Self-test failed: result=0x%08X\n", + nic->mem->selftest.result); + return -ETIMEDOUT; + } + if(nic->mem->selftest.signature == 0) { + DPRINTK(HW, ERR, "Self-test failed: timed out\n"); + return -ETIMEDOUT; + } + + return 0; +} + +static void e100_eeprom_write(struct nic *nic, u16 addr_len, u16 addr, u16 data) +{ + u32 cmd_addr_data[3]; + u8 ctrl; + int i, j; + + /* Three cmds: write/erase enable, write data, write/erase disable */ + cmd_addr_data[0] = op_ewen << (addr_len - 2); + cmd_addr_data[1] = (((op_write << addr_len) | addr) << 16) | data; + cmd_addr_data[2] = op_ewds << (addr_len - 2); + + /* Bit-bang cmds to write word to eeprom */ + for(j = 0; j < 3; j++) { + + /* Chip select */ + writeb(eecs | eesk, &nic->csr->eeprom_ctrl_lo); + e100_write_flush(nic); udelay(4); + + for(i = 31; i >= 0; i--) { + ctrl = (cmd_addr_data[j] & (1 << i)) ? + eecs | eedi : eecs; + writeb(ctrl, &nic->csr->eeprom_ctrl_lo); + e100_write_flush(nic); udelay(4); + writeb(ctrl | eesk, &nic->csr->eeprom_ctrl_lo); + e100_write_flush(nic); udelay(4); + } + /* Wait 10 msec for cmd to complete */ + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(HZ / 100 + 1); + + /* Chip deselect */ + writeb(0, &nic->csr->eeprom_ctrl_lo); + e100_write_flush(nic); udelay(4); + } + +}; + +/* General technique stolen from the eepro100 driver - very clever */ +static u16 e100_eeprom_read(struct nic *nic, u16 *addr_len, u16 addr) +{ + u32 cmd_addr_data; + u16 data = 0; + u8 ctrl; + int i; + + cmd_addr_data = ((op_read << *addr_len) | addr) << 16; + + /* Chip select */ + writeb(eecs | eesk, &nic->csr->eeprom_ctrl_lo); + e100_write_flush(nic); udelay(4); + + /* Bit-bang to read word from eeprom */ + for(i = 31; i >= 0; i--) { + ctrl = (cmd_addr_data & (1 << i)) ? eecs | eedi : eecs; + writeb(ctrl, &nic->csr->eeprom_ctrl_lo); + e100_write_flush(nic); udelay(4); + writeb(ctrl | eesk, &nic->csr->eeprom_ctrl_lo); + e100_write_flush(nic); udelay(4); + /* Eeprom drives a dummy zero to EEDO after receiving + * complete address. Use this to adjust addr_len. */ + ctrl = readb(&nic->csr->eeprom_ctrl_lo); + if(!(ctrl & eedo) && i > 16) { + *addr_len -= (i - 16); + i = 17; + } + data = (data << 1) | (ctrl & eedo ? 1 : 0); + } + + /* Chip deselect */ + writeb(0, &nic->csr->eeprom_ctrl_lo); + e100_write_flush(nic); udelay(4); + + return data; +}; + +/* Load entire EEPROM image into driver cache and validate checksum */ +static int e100_eeprom_load(struct nic *nic) +{ + u16 addr, addr_len = 8, checksum = 0; + + /* Try reading with an 8-bit addr len to discover actual addr len */ + e100_eeprom_read(nic, &addr_len, 0); + nic->eeprom_wc = 1 << addr_len; + + for(addr = 0; addr < nic->eeprom_wc; addr++) { + nic->eeprom[addr] = e100_eeprom_read(nic, &addr_len, addr); + if(addr < nic->eeprom_wc - 1) + checksum += nic->eeprom[addr]; + } + + /* The checksum, stored in the last word, is calculated such that + * the sum of words should be 0xBABA */ + checksum = 0xBABA - checksum; + if(checksum != nic->eeprom[nic->eeprom_wc - 1]) { + DPRINTK(PROBE, ERR, "EEPROM corrupted\n"); + return -EAGAIN; + } + + return 0; +} + +/* Save (portion of) driver EEPROM cache to device and update checksum */ +static int e100_eeprom_save(struct nic *nic, u16 start, u16 count) +{ + u16 addr, addr_len = 8, checksum = 0; + + /* Try reading with an 8-bit addr len to discover actual addr len */ + e100_eeprom_read(nic, &addr_len, 0); + nic->eeprom_wc = 1 << addr_len; + + if(start + count >= nic->eeprom_wc) + return -EINVAL; + + for(addr = start; addr < start + count; addr++) + e100_eeprom_write(nic, addr_len, addr, nic->eeprom[addr]); + + /* The checksum, stored in the last word, is calculated such that + * the sum of words should be 0xBABA */ + for(addr = 0; addr < nic->eeprom_wc - 1; addr++) + checksum += nic->eeprom[addr]; + nic->eeprom[nic->eeprom_wc - 1] = 0xBABA - checksum; + e100_eeprom_write(nic, addr_len, nic->eeprom_wc - 1, 0xBABA - checksum); + + return 0; +} + +#define E100_WAIT_SCB_TIMEOUT 40 +static inline int e100_exec_cmd(struct nic *nic, u8 cmd, dma_addr_t dma_addr) +{ + unsigned long flags; + unsigned int i; + int err = 0; + + spin_lock_irqsave(&nic->cmd_lock, flags); + + /* Previous command is accepted when SCB clears */ + for(i = 0; i < E100_WAIT_SCB_TIMEOUT; i++) { + if(likely(!readb(&nic->csr->scb.cmd_lo))) + break; + cpu_relax(); + if(unlikely(i > (E100_WAIT_SCB_TIMEOUT >> 1))) + udelay(5); + } + if(unlikely(i == E100_WAIT_SCB_TIMEOUT)) { + err = -EAGAIN; + goto err_unlock; + } + + if(unlikely(cmd != cuc_resume)) + writel(dma_addr, &nic->csr->scb.gen_ptr); + writeb(cmd, &nic->csr->scb.cmd_lo); + +err_unlock: + spin_unlock_irqrestore(&nic->cmd_lock, flags); + + return err; +} + +static inline int e100_exec_cb(struct nic *nic, struct sk_buff *skb, + void (*cb_prepare)(struct nic *, struct cb *, struct sk_buff *)) +{ + struct cb *cb; + unsigned long flags; + int err = 0; + + spin_lock_irqsave(&nic->cb_lock, flags); + + if(unlikely(!nic->cbs_avail)) { + err = -ENOMEM; + goto err_unlock; + } + + cb = nic->cb_to_use; + nic->cb_to_use = cb->next; + nic->cbs_avail--; + cb->skb = skb; + + if(unlikely(!nic->cbs_avail)) + err = -ENOSPC; + + cb_prepare(nic, cb, skb); + + /* Order is important otherwise we'll be in a race with h/w: + * set S-bit in current first, then clear S-bit in previous. */ + cb->command |= cpu_to_le16(cb_s); + cb->prev->command &= cpu_to_le16(~cb_s); + + while(nic->cb_to_send != nic->cb_to_use) { + if(unlikely((err = e100_exec_cmd(nic, nic->cuc_cmd, + nic->cb_to_send->dma_addr)))) { + /* Ok, here's where things get sticky. It's + * possible that we can't schedule the command + * because the controller is too busy, so + * let's just queue the command and try again + * when another command is scheduled. */ + break; + } else { + nic->cuc_cmd = cuc_resume; + nic->cb_to_send = nic->cb_to_send->next; + } + } + +err_unlock: + spin_unlock_irqrestore(&nic->cb_lock, flags); + + return err; +} + +static u16 mdio_ctrl(struct nic *nic, u32 addr, u32 dir, u32 reg, u16 data) +{ + u32 data_out = 0; + unsigned int i; + + writel((reg << 16) | (addr << 21) | dir | data, &nic->csr->mdi_ctrl); + + for(i = 0; i < 100; i++) { + udelay(20); + if((data_out = readl(&nic->csr->mdi_ctrl)) & mdi_ready) + break; + } + + DPRINTK(HW, DEBUG, + "%s:addr=%d, reg=%d, data_in=0x%04X, data_out=0x%04X\n", + dir == mdi_read ? "READ" : "WRITE", addr, reg, data, data_out); + return (u16)data_out; +} + +static int mdio_read(struct net_device *netdev, int addr, int reg) +{ + return mdio_ctrl(netdev->priv, addr, mdi_read, reg, 0); +} + +static void mdio_write(struct net_device *netdev, int addr, int reg, int data) +{ + mdio_ctrl(netdev->priv, addr, mdi_write, reg, data); +} + +static void e100_get_defaults(struct nic *nic) +{ + struct param_range rfds = { .min = 64, .max = 256, .count = 64 }; + struct param_range cbs = { .min = 64, .max = 256, .count = 64 }; + + pci_read_config_byte(nic->pdev, PCI_REVISION_ID, &nic->rev_id); + /* MAC type is encoded as rev ID; exception: ICH is treated as 82559 */ + nic->mac = (nic->flags & ich) ? mac_82559_D101M : nic->rev_id; + if(nic->mac == mac_unknown) + nic->mac = mac_82557_D100_A; + + nic->params.rfds = rfds; + nic->params.cbs = cbs; + + /* Quadwords to DMA into FIFO before starting frame transmit */ + nic->tx_threshold = 0xE0; + + nic->tx_command = cpu_to_le16(cb_tx | cb_i | cb_tx_sf | + ((nic->mac >= mac_82558_D101_A4) ? cb_cid : 0)); + + /* Template for a freshly allocated RFD */ + nic->blank_rfd.command = cpu_to_le16(cb_el); + nic->blank_rfd.rbd = 0xFFFFFFFF; + nic->blank_rfd.size = cpu_to_le16(VLAN_ETH_FRAME_LEN); + + /* MII setup */ + nic->mii.phy_id_mask = 0x1F; + nic->mii.reg_num_mask = 0x1F; + nic->mii.dev = nic->netdev; + nic->mii.mdio_read = mdio_read; + nic->mii.mdio_write = mdio_write; +} + +static void e100_configure(struct nic *nic, struct cb *cb, struct sk_buff *skb) +{ + struct config *config = &cb->u.config; + u8 *c = (u8 *)config; + + cb->command = cpu_to_le16(cb_config); + + memset(config, 0, sizeof(struct config)); + + config->byte_count = 0x16; /* bytes in this struct */ + config->rx_fifo_limit = 0x8; /* bytes in FIFO before DMA */ + config->direct_rx_dma = 0x1; /* reserved */ + config->standard_tcb = 0x1; /* 1=standard, 0=extended */ + config->standard_stat_counter = 0x1; /* 1=standard, 0=extended */ + config->rx_discard_short_frames = 0x1; /* 1=discard, 0=pass */ + config->tx_underrun_retry = 0x3; /* # of underrun retries */ + config->mii_mode = 0x1; /* 1=MII mode, 0=503 mode */ + config->pad10 = 0x6; + config->no_source_addr_insertion = 0x1; /* 1=no, 0=yes */ + config->preamble_length = 0x2; /* 0=1, 1=3, 2=7, 3=15 bytes */ + config->ifs = 0x6; /* x16 = inter frame spacing */ + config->ip_addr_hi = 0xF2; /* ARP IP filter - not used */ + config->pad15_1 = 0x1; + config->pad15_2 = 0x1; + config->crs_or_cdt = 0x0; /* 0=CRS only, 1=CRS or CDT */ + config->fc_delay_hi = 0x40; /* time delay for fc frame */ + config->tx_padding = 0x1; /* 1=pad short frames */ + config->fc_priority_threshold = 0x7; /* 7=priority fc disabled */ + config->pad18 = 0x1; + config->full_duplex_pin = 0x1; /* 1=examine FDX# pin */ + config->pad20_1 = 0x1F; + config->fc_priority_location = 0x1; /* 1=byte#31, 0=byte#19 */ + config->pad21_1 = 0x5; + + config->adaptive_ifs = nic->adaptive_ifs; + config->loopback = nic->loopback; + + if(nic->mii.force_media && nic->mii.full_duplex) + config->full_duplex_force = 0x1; /* 1=force, 0=auto */ + + if(nic->flags & promiscuous || nic->loopback) { + config->rx_save_bad_frames = 0x1; /* 1=save, 0=discard */ + config->rx_discard_short_frames = 0x0; /* 1=discard, 0=save */ + config->promiscuous_mode = 0x1; /* 1=on, 0=off */ + } + + if(nic->flags & multicast_all) + config->multicast_all = 0x1; /* 1=accept, 0=no */ + + if(!(nic->flags & wol_magic)) + config->magic_packet_disable = 0x1; /* 1=off, 0=on */ + + if(nic->mac >= mac_82558_D101_A4) { + config->fc_disable = 0x1; /* 1=Tx fc off, 0=Tx fc on */ + config->mwi_enable = 0x1; /* 1=enable, 0=disable */ + config->standard_tcb = 0x0; /* 1=standard, 0=extended */ + config->rx_long_ok = 0x1; /* 1=VLANs ok, 0=standard */ + if(nic->mac >= mac_82559_D101M) + config->tno_intr = 0x1; /* TCO stats enable */ + else + config->standard_stat_counter = 0x0; + } + + DPRINTK(HW, DEBUG, "[00-07]=%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n", + c[0], c[1], c[2], c[3], c[4], c[5], c[6], c[7]); + DPRINTK(HW, DEBUG, "[08-15]=%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n", + c[8], c[9], c[10], c[11], c[12], c[13], c[14], c[15]); + DPRINTK(HW, DEBUG, "[16-23]=%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n", + c[16], c[17], c[18], c[19], c[20], c[21], c[22], c[23]); +} + +static void e100_setup_iaaddr(struct nic *nic, struct cb *cb, + struct sk_buff *skb) +{ + cb->command = cpu_to_le16(cb_iaaddr); + memcpy(cb->u.iaaddr, nic->netdev->dev_addr, ETH_ALEN); +} + +static void e100_dump(struct nic *nic, struct cb *cb, struct sk_buff *skb) +{ + cb->command = cpu_to_le16(cb_dump); + cb->u.dump_buffer_addr = cpu_to_le32(nic->dma_addr + + offsetof(struct mem, dump_buf)); +} + +#define NCONFIG_AUTO_SWITCH 0x0080 +#define MII_NSC_CONG MII_RESV1 +#define NSC_CONG_ENABLE 0x0100 +#define NSC_CONG_TXREADY 0x0400 +#define ADVERTISE_FC_SUPPORTED 0x0400 +static int e100_phy_init(struct nic *nic) +{ + struct net_device *netdev = nic->netdev; + u32 addr; + u16 bmcr, stat, id_lo, id_hi, cong; + + /* Discover phy addr by searching addrs in order {1,0,2,..., 31} */ + for(addr = 0; addr < 32; addr++) { + nic->mii.phy_id = (addr == 0) ? 1 : (addr == 1) ? 0 : addr; + bmcr = mdio_read(netdev, nic->mii.phy_id, MII_BMCR); + stat = mdio_read(netdev, nic->mii.phy_id, MII_BMSR); + stat = mdio_read(netdev, nic->mii.phy_id, MII_BMSR); + if(!((bmcr == 0xFFFF) || ((stat == 0) && (bmcr == 0)))) + break; + } + DPRINTK(HW, DEBUG, "phy_addr = %d\n", nic->mii.phy_id); + if(addr == 32) + return -EAGAIN; + + /* Selected the phy and isolate the rest */ + for(addr = 0; addr < 32; addr++) { + if(addr != nic->mii.phy_id) { + mdio_write(netdev, addr, MII_BMCR, BMCR_ISOLATE); + } else { + bmcr = mdio_read(netdev, addr, MII_BMCR); + mdio_write(netdev, addr, MII_BMCR, + bmcr & ~BMCR_ISOLATE); + } + } + + /* Get phy ID */ + id_lo = mdio_read(netdev, nic->mii.phy_id, MII_PHYSID1); + id_hi = mdio_read(netdev, nic->mii.phy_id, MII_PHYSID2); + nic->phy = (u32)id_hi << 16 | (u32)id_lo; + DPRINTK(HW, DEBUG, "phy ID = 0x%08X\n", nic->phy); + + /* Handle National tx phy */ + if(nic->phy == phy_nsc_tx) { + /* Disable congestion control */ + cong = mdio_read(netdev, nic->mii.phy_id, MII_NSC_CONG); + cong |= NSC_CONG_TXREADY; + cong &= ~NSC_CONG_ENABLE; + mdio_write(netdev, nic->mii.phy_id, MII_NSC_CONG, cong); + } + + if(nic->mac >= mac_82550_D102) + /* enable/disable MDI/MDI-X auto-switching */ + mdio_write(netdev, nic->mii.phy_id, MII_NCONFIG, + nic->mii.force_media ? 0 : NCONFIG_AUTO_SWITCH); + + return 0; +} + +static int e100_hw_init(struct nic *nic) +{ + int err; + + e100_hw_reset(nic); + + DPRINTK(HW, ERR, "e100_hw_init\n"); + if(!in_interrupt() && (err = e100_self_test(nic))) + return err; + + if((err = e100_phy_init(nic))) + return err; + if((err = e100_exec_cmd(nic, cuc_load_base, 0))) + return err; + if((err = e100_exec_cmd(nic, ruc_load_base, 0))) + return err; + if((err = e100_exec_cb(nic, NULL, e100_configure))) + return err; + if((err = e100_exec_cb(nic, NULL, e100_setup_iaaddr))) + return err; + if((err = e100_exec_cmd(nic, cuc_dump_addr, + nic->dma_addr + offsetof(struct mem, stats)))) + return err; + if((err = e100_exec_cmd(nic, cuc_dump_reset, 0))) + return err; + + e100_disable_irq(nic); + + return 0; +} + +static void e100_multi(struct nic *nic, struct cb *cb, struct sk_buff *skb) +{ + struct net_device *netdev = nic->netdev; + struct dev_mc_list *list = netdev->mc_list; + u16 i, count = min(netdev->mc_count, E100_MAX_MULTICAST_ADDRS); + + cb->command = cpu_to_le16(cb_multi); + cb->u.multi.count = cpu_to_le16(count * ETH_ALEN); + for(i = 0; list && i < count; i++, list = list->next) + memcpy(&cb->u.multi.addr[i*ETH_ALEN], &list->dmi_addr, + ETH_ALEN); +} + +static void e100_set_multicast_list(struct net_device *netdev) +{ + struct nic *nic = netdev->priv; + + DPRINTK(HW, DEBUG, "mc_count=%d, flags=0x%04X\n", + netdev->mc_count, netdev->flags); + + if(netdev->flags & IFF_PROMISC) + nic->flags |= promiscuous; + else + nic->flags &= ~promiscuous; + + if(netdev->flags & IFF_ALLMULTI || + netdev->mc_count > E100_MAX_MULTICAST_ADDRS) + nic->flags |= multicast_all; + else + nic->flags &= ~multicast_all; + + e100_exec_cb(nic, NULL, e100_configure); + e100_exec_cb(nic, NULL, e100_multi); +} + +static void e100_update_stats(struct nic *nic) +{ + struct net_device_stats *ns = &nic->net_stats; + struct stats *s = &nic->mem->stats; + u32 *complete = (nic->mac < mac_82558_D101_A4) ? &s->fc_xmt_pause : + (nic->mac < mac_82559_D101M) ? (u32 *)&s->xmt_tco_frames : + &s->complete; + + /* Device's stats reporting may take several microseconds to + * complete, so where always waiting for results of the + * previous command. */ + + if(*complete == le32_to_cpu(0x0000A007)) { + *complete = 0; + nic->tx_frames = le32_to_cpu(s->tx_good_frames); + nic->tx_collisions = le32_to_cpu(s->tx_total_collisions); + ns->tx_aborted_errors += le32_to_cpu(s->tx_max_collisions); + ns->tx_window_errors += le32_to_cpu(s->tx_late_collisions); + ns->tx_carrier_errors += le32_to_cpu(s->tx_lost_crs); + ns->tx_fifo_errors += le32_to_cpu(s->tx_underruns); + ns->collisions += nic->tx_collisions; + ns->tx_errors += le32_to_cpu(s->tx_max_collisions) + + le32_to_cpu(s->tx_lost_crs); + ns->rx_dropped += le32_to_cpu(s->rx_resource_errors); + ns->rx_length_errors += le32_to_cpu(s->rx_short_frame_errors); + ns->rx_over_errors += le32_to_cpu(s->rx_resource_errors); + ns->rx_crc_errors += le32_to_cpu(s->rx_crc_errors); + ns->rx_frame_errors += le32_to_cpu(s->rx_alignment_errors); + ns->rx_fifo_errors += le32_to_cpu(s->rx_overrun_errors); + ns->rx_errors += le32_to_cpu(s->rx_crc_errors) + + le32_to_cpu(s->rx_alignment_errors) + + le32_to_cpu(s->rx_short_frame_errors) + + le32_to_cpu(s->rx_cdt_errors); + nic->tx_deferred += le32_to_cpu(s->tx_deferred); + nic->tx_single_collisions += + le32_to_cpu(s->tx_single_collisions); + nic->tx_multiple_collisions += + le32_to_cpu(s->tx_multiple_collisions); + if(nic->mac >= mac_82558_D101_A4) { + nic->tx_fc_pause += le32_to_cpu(s->fc_xmt_pause); + nic->rx_fc_pause += le32_to_cpu(s->fc_rcv_pause); + nic->rx_fc_unsupported += + le32_to_cpu(s->fc_rcv_unsupported); + if(nic->mac >= mac_82559_D101M) { + nic->tx_tco_frames += + le16_to_cpu(s->xmt_tco_frames); + nic->rx_tco_frames += + le16_to_cpu(s->rcv_tco_frames); + } + } + } + + e100_exec_cmd(nic, cuc_dump_reset, 0); +} + +static void e100_adjust_adaptive_ifs(struct nic *nic, int speed, int duplex) +{ + /* Adjust inter-frame-spacing (IFS) between two transmits if + * we're getting collisions on a half-duplex connection. */ + + if(duplex == DUPLEX_HALF) { + u32 prev = nic->adaptive_ifs; + u32 min_frames = (speed == SPEED_100) ? 1000 : 100; + + if((nic->tx_frames / 32 < nic->tx_collisions) && + (nic->tx_frames > min_frames)) { + if(nic->adaptive_ifs < 60) + nic->adaptive_ifs += 5; + } else if (nic->tx_frames < min_frames) { + if(nic->adaptive_ifs >= 5) + nic->adaptive_ifs -= 5; + } + if(nic->adaptive_ifs != prev) + e100_exec_cb(nic, NULL, e100_configure); + } +} + +static void e100_watchdog(unsigned long data) +{ + struct nic *nic = (struct nic *)data; + struct ethtool_cmd cmd; + + DPRINTK(TIMER, DEBUG, "right now = %ld\n", jiffies); + + /* mii library handles link maintenance tasks */ + + mii_ethtool_gset(&nic->mii, &cmd); + + if(mii_link_ok(&nic->mii) && !netif_carrier_ok(nic->netdev)) { + DPRINTK(LINK, INFO, "link up, %sMbps, %s-duplex\n", + cmd.speed == SPEED_100 ? "100" : "10", + cmd.duplex == DUPLEX_FULL ? "full" : "half"); + } else if(!mii_link_ok(&nic->mii) && netif_carrier_ok(nic->netdev)) { + DPRINTK(LINK, INFO, "link down\n"); + } + + mii_check_link(&nic->mii); + + /* Software generated interrupt to recover from (rare) Rx + * allocation failure */ + writeb(irq_sw_gen, &nic->csr->scb.cmd_hi); + e100_write_flush(nic); + + e100_update_stats(nic); + e100_adjust_adaptive_ifs(nic, cmd.speed, cmd.duplex); + + if(nic->mac <= mac_82557_D100_C) + /* Issue a multicast command to workaround a 557 lock up */ + e100_set_multicast_list(nic->netdev); + + mod_timer(&nic->watchdog, jiffies + E100_WATCHDOG_PERIOD); +} + +static inline void e100_xmit_prepare(struct nic *nic, struct cb *cb, + struct sk_buff *skb) +{ + cb->command = nic->tx_command; + cb->u.tcb.tbd_array = cb->dma_addr + offsetof(struct cb, u.tcb.tbd); + cb->u.tcb.tcb_byte_count = 0; + cb->u.tcb.threshold = nic->tx_threshold; + cb->u.tcb.tbd_count = 1; + cb->u.tcb.tbd.buf_addr = cpu_to_le32(pci_map_single(nic->pdev, + skb->data, skb->len, PCI_DMA_TODEVICE)); + cb->u.tcb.tbd.size = cpu_to_le16(skb->len); +} + +static int e100_xmit_frame(struct sk_buff *skb, struct net_device *netdev) +{ + struct nic *nic = netdev->priv; + int err = e100_exec_cb(nic, skb, e100_xmit_prepare); + + switch(err) { + case -ENOSPC: + /* We queued the skb, but now we're out of space. */ + netif_stop_queue(netdev); + break; + case -ENOMEM: + /* This is a hard error - log it. */ + DPRINTK(TX_ERR, DEBUG, "Out of Tx resources, returning skb\n"); + netif_stop_queue(netdev); + return 1; + } + + netdev->trans_start = jiffies; + return 0; +} + +static inline int e100_tx_clean(struct nic *nic) +{ + struct cb *cb; + int tx_cleaned = 0; + + spin_lock(&nic->cb_lock); + + DPRINTK(TX_DONE, DEBUG, "cb->status = 0x%04X\n", + nic->cb_to_clean->status); + + /* Clean CBs marked complete */ + for(cb = nic->cb_to_clean; + cb->status & cpu_to_le16(cb_complete); + cb = nic->cb_to_clean = cb->next) { + if(likely(cb->skb)) { + nic->net_stats.tx_packets++; + nic->net_stats.tx_bytes += cb->skb->len; + + pci_unmap_single(nic->pdev, + le32_to_cpu(cb->u.tcb.tbd.buf_addr), + le16_to_cpu(cb->u.tcb.tbd.size), + PCI_DMA_TODEVICE); + dev_kfree_skb_any(cb->skb); + tx_cleaned = 1; + } + cb->status = 0; + nic->cbs_avail++; + } + + spin_unlock(&nic->cb_lock); + + /* Recover from running out of Tx resources in xmit_frame */ + if(unlikely(tx_cleaned && netif_queue_stopped(nic->netdev))) + netif_wake_queue(nic->netdev); + + return tx_cleaned; +} + +static void e100_clean_cbs(struct nic *nic) +{ + if(nic->cbs) { + while(nic->cb_to_clean != nic->cb_to_use) { + struct cb *cb = nic->cb_to_clean; + if(cb->skb) { + pci_unmap_single(nic->pdev, + le32_to_cpu(cb->u.tcb.tbd.buf_addr), + le16_to_cpu(cb->u.tcb.tbd.size), + PCI_DMA_TODEVICE); + dev_kfree_skb(cb->skb); + } + nic->cb_to_clean = nic->cb_to_clean->next; + } + nic->cbs_avail = nic->params.cbs.count; + pci_free_consistent(nic->pdev, + sizeof(struct cb) * nic->params.cbs.count, + nic->cbs, nic->cbs_dma_addr); + nic->cbs = NULL; + nic->cbs_avail = 0; + } + nic->cuc_cmd = cuc_start; + nic->cb_to_use = nic->cb_to_send = nic->cb_to_clean = + nic->cbs; +} + +static int e100_alloc_cbs(struct nic *nic) +{ + struct cb *cb; + unsigned int i, count = nic->params.cbs.count; + + nic->cuc_cmd = cuc_start; + nic->cb_to_use = nic->cb_to_send = nic->cb_to_clean = NULL; + nic->cbs_avail = 0; + + nic->cbs = pci_alloc_consistent(nic->pdev, + sizeof(struct cb) * count, &nic->cbs_dma_addr); + if(!nic->cbs) + return -ENOMEM; + + for(cb = nic->cbs, i = 0; i < count; cb++, i++) { + cb->next = (i + 1 < count) ? cb + 1 : nic->cbs; + cb->prev = (i == 0) ? nic->cbs + count - 1 : cb - 1; + + cb->dma_addr = nic->cbs_dma_addr + i * sizeof(struct cb); + cb->link = cpu_to_le32(nic->cbs_dma_addr + + ((i+1) % count) * sizeof(struct cb)); + } + + nic->cb_to_use = nic->cb_to_send = nic->cb_to_clean = nic->cbs; + nic->cbs_avail = count; + + return 0; +} + +static inline void e100_start_receiver(struct nic *nic) +{ + /* (Re)start RU if suspended or idle and RFA is non-NULL */ + if(!nic->ru_running && nic->rx_to_clean->skb) { + e100_exec_cmd(nic, ruc_start, nic->rx_to_clean->dma_addr); + nic->ru_running = 1; + } +} + +#define RFD_BUF_LEN (sizeof(struct rfd) + VLAN_ETH_FRAME_LEN) +static inline int e100_rx_alloc_skb(struct nic *nic, struct rx *rx) +{ + unsigned int rx_offset = 2; /* u32 align protocol headers */ + + if(!(rx->skb = dev_alloc_skb(RFD_BUF_LEN + rx_offset))) + return -ENOMEM; + + /* Align, init, and map the RFA. */ + rx->skb->dev = nic->netdev; + skb_reserve(rx->skb, rx_offset); + memcpy(rx->skb->data, &nic->blank_rfd, sizeof(struct rfd)); + rx->dma_addr = pci_map_single(nic->pdev, rx->skb->data, + RFD_BUF_LEN, PCI_DMA_FROMDEVICE); + + /* Link the RFD to end of RFA by linking previous RFD to + * this one, and clearing EL bit of previous. */ + if(rx->prev->skb) { + struct rfd *prev_rfd = (struct rfd *)rx->prev->skb->data; + put_unaligned(cpu_to_le32(rx->dma_addr), + (u32 *)&prev_rfd->link); + prev_rfd->command &= ~cpu_to_le16(cb_el); + pci_dma_sync_single(nic->pdev, rx->prev->dma_addr, + sizeof(struct rfd), PCI_DMA_TODEVICE); + } + + return 0; +} + +static inline int e100_rx_indicate(struct nic *nic, struct rx *rx, + unsigned int *work_done, unsigned int work_to_do) +{ + struct sk_buff *skb = rx->skb; + struct rfd *rfd = (struct rfd *)skb->data; + u16 rfd_status, actual_size; + + if(unlikely(work_done && *work_done >= work_to_do)) + return -EAGAIN; + + /* Need to sync before taking a peek at cb_complete bit */ + pci_dma_sync_single(nic->pdev, rx->dma_addr, + sizeof(struct rfd), PCI_DMA_FROMDEVICE); + rfd_status = le16_to_cpu(rfd->status); + + DPRINTK(RX_STATUS, DEBUG, "status=0x%04X\n", rfd_status); + + /* If data isn't ready, nothing to indicate */ + if(unlikely(!(rfd_status & cb_complete))) + return -EAGAIN; + + /* Get actual data size */ + actual_size = le16_to_cpu(rfd->actual_size) & 0x3FFF; + if(unlikely(actual_size > RFD_BUF_LEN - sizeof(struct rfd))) + actual_size = RFD_BUF_LEN - sizeof(struct rfd); + + /* Get data */ + pci_dma_sync_single(nic->pdev, rx->dma_addr, + sizeof(struct rfd) + actual_size, + PCI_DMA_FROMDEVICE); + pci_unmap_single(nic->pdev, rx->dma_addr, + RFD_BUF_LEN, PCI_DMA_FROMDEVICE); + + /* Pull off the RFD and put the actual data (minus eth hdr) */ + skb_reserve(skb, sizeof(struct rfd)); + skb_put(skb, actual_size); + skb->protocol = eth_type_trans(skb, nic->netdev); + + if(unlikely(!(rfd_status & cb_ok)) || + actual_size > nic->netdev->mtu + VLAN_ETH_HLEN) { + /* Don't indicate if errors */ + dev_kfree_skb_any(skb); + } else { + nic->net_stats.rx_packets++; + nic->net_stats.rx_bytes += actual_size; + nic->netdev->last_rx = jiffies; +#ifdef CONFIG_E100_NAPI + netif_receive_skb(skb); +#else + netif_rx(skb); +#endif + if(work_done) + (*work_done)++; + } + + rx->skb = NULL; + + return 0; +} + +static inline void e100_rx_clean(struct nic *nic, unsigned int *work_done, + unsigned int work_to_do) +{ + struct rx *rx; + + /* Indicate newly arrived packets */ + for(rx = nic->rx_to_clean; rx->skb; rx = nic->rx_to_clean = rx->next) { + if(e100_rx_indicate(nic, rx, work_done, work_to_do)) + break; /* No more to clean */ + } + + /* Alloc new skbs to refill list */ + for(rx = nic->rx_to_use; !rx->skb; rx = nic->rx_to_use = rx->next) { + if(unlikely(e100_rx_alloc_skb(nic, rx))) + break; /* Better luck next time (see watchdog) */ + } + + e100_start_receiver(nic); +} + +static void e100_rx_clean_list(struct nic *nic) +{ + struct rx *rx; + unsigned int i, count = nic->params.rfds.count; + + if(nic->rxs) { + for(rx = nic->rxs, i = 0; i < count; rx++, i++) { + if(rx->skb) { + pci_unmap_single(nic->pdev, rx->dma_addr, + RFD_BUF_LEN, PCI_DMA_FROMDEVICE); + dev_kfree_skb(rx->skb); + } + } + kfree(nic->rxs); + nic->rxs = NULL; + } + + nic->rx_to_use = nic->rx_to_clean = NULL; + nic->ru_running = 0; +} + +static int e100_rx_alloc_list(struct nic *nic) +{ + struct rx *rx; + unsigned int i, count = nic->params.rfds.count; + + nic->rx_to_use = nic->rx_to_clean = NULL; + + if(!(nic->rxs = kmalloc(sizeof(struct rx) * count, GFP_ATOMIC))) + return -ENOMEM; + memset(nic->rxs, 0, sizeof(struct rx) * count); + + for(rx = nic->rxs, i = 0; i < count; rx++, i++) { + rx->next = (i + 1 < count) ? rx + 1 : nic->rxs; + rx->prev = (i == 0) ? nic->rxs + count - 1 : rx - 1; + if(e100_rx_alloc_skb(nic, rx)) { + e100_rx_clean_list(nic); + return -ENOMEM; + } + } + + nic->rx_to_use = nic->rx_to_clean = nic->rxs; + + return 0; +} + +static irqreturn_t e100_intr(int irq, void *dev_id, struct pt_regs *regs) +{ + struct net_device *netdev = dev_id; + struct nic *nic = netdev->priv; + u8 stat_ack = readb(&nic->csr->scb.stat_ack); + + DPRINTK(INTR, DEBUG, "stat_ack = 0x%02X\n", stat_ack); + + if(stat_ack == stat_ack_not_ours || /* Not our interrupt */ + stat_ack == stat_ack_not_present) /* Hardware is ejected */ + return IRQ_NONE; + + /* Ack interrupt(s) */ + writeb(stat_ack, &nic->csr->scb.stat_ack); + + /* We hit Receive No Resource (RNR); restart RU after cleaning */ + if(stat_ack & stat_ack_rnr) + nic->ru_running = 0; + +#ifdef CONFIG_E100_NAPI + e100_disable_irq(nic); + netif_rx_schedule(netdev); +#else + if(stat_ack & stat_ack_rx) + e100_rx_clean(nic, NULL, 0); + if(stat_ack & stat_ack_tx) + e100_tx_clean(nic); +#endif + + return IRQ_HANDLED; +} + +#ifdef CONFIG_E100_NAPI +static int e100_poll(struct net_device *netdev, int *budget) +{ + struct nic *nic = netdev->priv; + unsigned int work_to_do = min(netdev->quota, *budget); + unsigned int work_done = 0; + int tx_cleaned; + + e100_rx_clean(nic, &work_done, work_to_do); + tx_cleaned = e100_tx_clean(nic); + + /* If no Rx and Tx cleanup work was done, exit polling mode. */ + if((!tx_cleaned && (work_done == 0)) || !netif_running(netdev)) { + netif_rx_complete(netdev); + e100_enable_irq(nic); + return 0; + } + + *budget -= work_done; + netdev->quota -= work_done; + + return 1; +} +#endif + +#ifdef CONFIG_NET_POLL_CONTROLLER +static void e100_netpoll(struct net_device *netdev) +{ + struct nic *nic = netdev->priv; + e100_disable_irq(nic); + e100_intr(nic->pdev->irq, netdev, NULL); + e100_enable_irq(nic); +} +#endif + +static struct net_device_stats *e100_get_stats(struct net_device *netdev) +{ + struct nic *nic = netdev->priv; + return &nic->net_stats; +} + +static int e100_set_mac_address(struct net_device *netdev, void *p) +{ + struct nic *nic = netdev->priv; + struct sockaddr *addr = p; + + if (!is_valid_ether_addr(addr->sa_data)) + return -EADDRNOTAVAIL; + + memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len); + e100_exec_cb(nic, NULL, e100_setup_iaaddr); + + return 0; +} + +static int e100_change_mtu(struct net_device *netdev, int new_mtu) +{ + if(new_mtu < ETH_ZLEN || new_mtu > ETH_DATA_LEN) + return -EINVAL; + netdev->mtu = new_mtu; + return 0; +} + +static int e100_asf(struct nic *nic) +{ + /* ASF can be enabled from eeprom */ + return((nic->pdev->device >= 0x1050) && (nic->pdev->device <= 0x1055) && + (nic->eeprom[eeprom_config_asf] & eeprom_asf) && + !(nic->eeprom[eeprom_config_asf] & eeprom_gcl) && + ((nic->eeprom[eeprom_smbus_addr] & 0xFF) != 0xFE)); +} + +static int e100_up(struct nic *nic) +{ + int err; + + if((err = e100_rx_alloc_list(nic))) + return err; + if((err = e100_alloc_cbs(nic))) + goto err_rx_clean_list; + if((err = e100_hw_init(nic))) + goto err_clean_cbs; + e100_set_multicast_list(nic->netdev); + e100_start_receiver(nic); + netif_start_queue(nic->netdev); + mod_timer(&nic->watchdog, jiffies); + if((err = request_irq(nic->pdev->irq, e100_intr, SA_SHIRQ, + nic->netdev->name, nic->netdev))) + goto err_no_irq; + e100_enable_irq(nic); + return 0; + +err_no_irq: + del_timer_sync(&nic->watchdog); + netif_stop_queue(nic->netdev); +err_clean_cbs: + e100_clean_cbs(nic); +err_rx_clean_list: + e100_rx_clean_list(nic); + return err; +} + +static void e100_down(struct nic *nic) +{ + e100_hw_reset(nic); + free_irq(nic->pdev->irq, nic->netdev); + del_timer_sync(&nic->watchdog); + netif_carrier_off(nic->netdev); + netif_stop_queue(nic->netdev); + e100_clean_cbs(nic); + e100_rx_clean_list(nic); +} + +static void e100_tx_timeout(struct net_device *netdev) +{ + struct nic *nic = netdev->priv; + + DPRINTK(TX_ERR, DEBUG, "scb.status=0x%02X\n", + readb(&nic->csr->scb.status)); + e100_down(netdev->priv); + e100_up(netdev->priv); +} + +static int e100_loopback_test(struct nic *nic, enum loopback loopback_mode) +{ + int err; + struct sk_buff *skb; + + /* Use driver resources to perform internal MAC or PHY + * loopback test. A single packet is prepared and transmitted + * in loopback mode, and the test passes if the received + * packet compares byte-for-byte to the transmitted packet. */ + + if((err = e100_rx_alloc_list(nic))) + return err; + if((err = e100_alloc_cbs(nic))) + goto err_clean_rx; + + /* ICH PHY loopback is broken so do MAC loopback instead */ + if(nic->flags & ich && loopback_mode == lb_phy) + loopback_mode = lb_mac; + + nic->loopback = loopback_mode; + if((err = e100_hw_init(nic))) + goto err_loopback_none; + + if(loopback_mode == lb_phy) + mdio_write(nic->netdev, nic->mii.phy_id, MII_BMCR, + BMCR_LOOPBACK); + + e100_start_receiver(nic); + + if(!(skb = dev_alloc_skb(ETH_DATA_LEN))) { + err = -ENOMEM; + goto err_loopback_none; + } + skb_put(skb, ETH_DATA_LEN); + memset(skb->data, 0xFF, ETH_DATA_LEN); + e100_xmit_frame(skb, nic->netdev); + + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(HZ / 100 + 1); + + if(memcmp(nic->rx_to_clean->skb->data + sizeof(struct rfd), + skb->data, ETH_DATA_LEN)) + err = -EAGAIN; + +err_loopback_none: + mdio_write(nic->netdev, nic->mii.phy_id, MII_BMCR, 0); + nic->loopback = lb_none; + e100_hw_init(nic); + e100_clean_cbs(nic); +err_clean_rx: + e100_rx_clean_list(nic); + return err; +} + +#define MII_LED_CONTROL 0x1B +static void e100_blink_led(unsigned long data) +{ + struct nic *nic = (struct nic *)data; + enum led_state { + led_on = 0x01, + led_off = 0x04, + led_on_559 = 0x05, + led_on_557 = 0x07, + }; + + nic->leds = (nic->leds & led_on) ? led_off : + (nic->mac < mac_82559_D101M) ? led_on_557 : led_on_559; + mdio_write(nic->netdev, nic->mii.phy_id, MII_LED_CONTROL, nic->leds); + mod_timer(&nic->blink_timer, jiffies + HZ / 4); +} + +static int e100_get_settings(struct net_device *netdev, struct ethtool_cmd *cmd) +{ + struct nic *nic = netdev->priv; + return mii_ethtool_gset(&nic->mii, cmd); +} + +static int e100_set_settings(struct net_device *netdev, struct ethtool_cmd *cmd) +{ + struct nic *nic = netdev->priv; + int err; + + mdio_write(netdev, nic->mii.phy_id, MII_BMCR, BMCR_RESET); + err = mii_ethtool_sset(&nic->mii, cmd); + e100_exec_cb(nic, NULL, e100_configure); + + return err; +} + +static void e100_get_drvinfo(struct net_device *netdev, + struct ethtool_drvinfo *info) +{ + struct nic *nic = netdev->priv; + strcpy(info->driver, DRV_NAME); + strcpy(info->version, DRV_VERSION); + strcpy(info->fw_version, "N/A"); + strcpy(info->bus_info, pci_name(nic->pdev)); +} + +static int e100_get_regs_len(struct net_device *netdev) +{ + struct nic *nic = netdev->priv; +#define E100_PHY_REGS 0x1C +#define E100_REGS_LEN 1 + E100_PHY_REGS + \ + sizeof(nic->mem->dump_buf) / sizeof(u32) + return E100_REGS_LEN * sizeof(u32); +} + +static void e100_get_regs(struct net_device *netdev, + struct ethtool_regs *regs, void *p) +{ + struct nic *nic = netdev->priv; + u32 *buff = p; + int i; + + regs->version = (1 << 24) | nic->rev_id; + buff[0] = readb(&nic->csr->scb.cmd_hi) << 24 | + readb(&nic->csr->scb.cmd_lo) << 16 | + readw(&nic->csr->scb.status); + for(i = E100_PHY_REGS; i >= 0; i--) + buff[1 + E100_PHY_REGS - i] = + mdio_read(netdev, nic->mii.phy_id, i); + memset(nic->mem->dump_buf, 0, sizeof(nic->mem->dump_buf)); + e100_exec_cb(nic, NULL, e100_dump); + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(HZ / 100 + 1); + memcpy(&buff[2 + E100_PHY_REGS], nic->mem->dump_buf, + sizeof(nic->mem->dump_buf)); +} + +static void e100_get_wol(struct net_device *netdev, struct ethtool_wolinfo *wol) +{ + struct nic *nic = netdev->priv; + wol->supported = (nic->mac >= mac_82558_D101_A4) ? WAKE_MAGIC : 0; + wol->wolopts = (nic->flags & wol_magic) ? WAKE_MAGIC : 0; +} + +static int e100_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol) +{ + struct nic *nic = netdev->priv; + + if(wol->wolopts != WAKE_MAGIC && wol->wolopts != 0) + return -EOPNOTSUPP; + + if(wol->wolopts) + nic->flags |= wol_magic; + else + nic->flags &= ~wol_magic; + + pci_enable_wake(nic->pdev, 0, nic->flags & (wol_magic | e100_asf(nic))); + e100_exec_cb(nic, NULL, e100_configure); + + return 0; +} + +static u32 e100_get_msglevel(struct net_device *netdev) +{ + struct nic *nic = netdev->priv; + return nic->msg_enable; +} + +static void e100_set_msglevel(struct net_device *netdev, u32 value) +{ + struct nic *nic = netdev->priv; + nic->msg_enable = value; +} + +static int e100_nway_reset(struct net_device *netdev) +{ + struct nic *nic = netdev->priv; + return mii_nway_restart(&nic->mii); +} + +static u32 e100_get_link(struct net_device *netdev) +{ + struct nic *nic = netdev->priv; + return mii_link_ok(&nic->mii); +} + +static int e100_get_eeprom_len(struct net_device *netdev) +{ + struct nic *nic = netdev->priv; + return nic->eeprom_wc << 1; +} + +#define E100_EEPROM_MAGIC 0x1234 +static int e100_get_eeprom(struct net_device *netdev, + struct ethtool_eeprom *eeprom, u8 *bytes) +{ + struct nic *nic = netdev->priv; + + eeprom->magic = E100_EEPROM_MAGIC; + memcpy(bytes, &((u8 *)nic->eeprom)[eeprom->offset], eeprom->len); + + return 0; +} + +static int e100_set_eeprom(struct net_device *netdev, + struct ethtool_eeprom *eeprom, u8 *bytes) +{ + struct nic *nic = netdev->priv; + + if(eeprom->magic != E100_EEPROM_MAGIC) + return -EINVAL; + memcpy(&((u8 *)nic->eeprom)[eeprom->offset], bytes, eeprom->len); + + return e100_eeprom_save(nic, eeprom->offset >> 1, + (eeprom->len >> 1) + 1); +} + +static void e100_get_ringparam(struct net_device *netdev, + struct ethtool_ringparam *ring) +{ + struct nic *nic = netdev->priv; + struct param_range *rfds = &nic->params.rfds; + struct param_range *cbs = &nic->params.cbs; + + ring->rx_max_pending = rfds->max; + ring->tx_max_pending = cbs->max; + ring->rx_mini_max_pending = 0; + ring->rx_jumbo_max_pending = 0; + ring->rx_pending = rfds->count; + ring->tx_pending = cbs->count; + ring->rx_mini_pending = 0; + ring->rx_jumbo_pending = 0; +} + +static int e100_set_ringparam(struct net_device *netdev, + struct ethtool_ringparam *ring) +{ + struct nic *nic = netdev->priv; + struct param_range *rfds = &nic->params.rfds; + struct param_range *cbs = &nic->params.cbs; + + if(netif_running(netdev)) + e100_down(nic); + rfds->count = max(ring->rx_pending, rfds->min); + rfds->count = min(rfds->count, rfds->max); + cbs->count = max(ring->tx_pending, cbs->min); + cbs->count = min(cbs->count, cbs->max); + if(netif_running(netdev)) + e100_up(nic); + + return 0; +} + +static const char e100_gstrings_test[][ETH_GSTRING_LEN] = { + "Link test (on/offline)", + "Eeprom test (on/offline)", + "Self test (offline)", + "Mac loopback (offline)", + "Phy loopback (offline)", +}; +#define E100_TEST_LEN sizeof(e100_gstrings_test) / ETH_GSTRING_LEN + +static int e100_diag_test_count(struct net_device *netdev) +{ + return E100_TEST_LEN; +} + +static void e100_diag_test(struct net_device *netdev, + struct ethtool_test *test, u64 *data) +{ + struct nic *nic = netdev->priv; + int i; + + memset(data, 0, E100_TEST_LEN * sizeof(u64)); + data[0] = !mii_link_ok(&nic->mii); + data[1] = e100_eeprom_load(nic); + if(test->flags & ETH_TEST_FL_OFFLINE) { + if(netif_running(netdev)) + e100_down(nic); + data[2] = e100_self_test(nic); + data[3] = e100_loopback_test(nic, lb_mac); + data[4] = e100_loopback_test(nic, lb_phy); + if(netif_running(netdev)) + e100_up(nic); + } + for(i = 0; i < E100_TEST_LEN; i++) + test->flags |= data[i] ? ETH_TEST_FL_FAILED : 0; +} + +static int e100_phys_id(struct net_device *netdev, u32 data) +{ + struct nic *nic = netdev->priv; + + if(!data || data > (u32)(MAX_SCHEDULE_TIMEOUT / HZ)) + data = (u32)(MAX_SCHEDULE_TIMEOUT / HZ); + mod_timer(&nic->blink_timer, jiffies); + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(data * HZ); + del_timer_sync(&nic->blink_timer); + mdio_write(netdev, nic->mii.phy_id, MII_LED_CONTROL, 0); + + return 0; +} + +static const char e100_gstrings_stats[][ETH_GSTRING_LEN] = { + "rx_packets", "tx_packets", "rx_bytes", "tx_bytes", "rx_errors", + "tx_errors", "rx_dropped", "tx_dropped", "multicast", "collisions", + "rx_length_errors", "rx_over_errors", "rx_crc_errors", + "rx_frame_errors", "rx_fifo_errors", "rx_missed_errors", + "tx_aborted_errors", "tx_carrier_errors", "tx_fifo_errors", + "tx_heartbeat_errors", "tx_window_errors", + /* device-specific stats */ + "tx_deferred", "tx_single_collisions", "tx_multi_collisions", + "tx_flow_control_pause", "rx_flow_control_pause", + "rx_flow_control_unsupported", "tx_tco_packets", "rx_tco_packets", +}; +#define E100_NET_STATS_LEN 21 +#define E100_STATS_LEN sizeof(e100_gstrings_stats) / ETH_GSTRING_LEN + +static int e100_get_stats_count(struct net_device *netdev) +{ + return E100_STATS_LEN; +} + +static void e100_get_ethtool_stats(struct net_device *netdev, + struct ethtool_stats *stats, u64 *data) +{ + struct nic *nic = netdev->priv; + int i; + + for(i = 0; i < E100_NET_STATS_LEN; i++) + data[i] = ((unsigned long *)&nic->net_stats)[i]; + + data[i++] = nic->tx_deferred; + data[i++] = nic->tx_single_collisions; + data[i++] = nic->tx_multiple_collisions; + data[i++] = nic->tx_fc_pause; + data[i++] = nic->rx_fc_pause; + data[i++] = nic->rx_fc_unsupported; + data[i++] = nic->tx_tco_frames; + data[i++] = nic->rx_tco_frames; +} + +static void e100_get_strings(struct net_device *netdev, u32 stringset, u8 *data) +{ + switch(stringset) { + case ETH_SS_TEST: + memcpy(data, *e100_gstrings_test, sizeof(e100_gstrings_test)); + break; + case ETH_SS_STATS: + memcpy(data, *e100_gstrings_stats, sizeof(e100_gstrings_stats)); + break; + } +} + +static struct ethtool_ops e100_ethtool_ops = { + .get_settings = e100_get_settings, + .set_settings = e100_set_settings, + .get_drvinfo = e100_get_drvinfo, + .get_regs_len = e100_get_regs_len, + .get_regs = e100_get_regs, + .get_wol = e100_get_wol, + .set_wol = e100_set_wol, + .get_msglevel = e100_get_msglevel, + .set_msglevel = e100_set_msglevel, + .nway_reset = e100_nway_reset, + .get_link = e100_get_link, + .get_eeprom_len = e100_get_eeprom_len, + .get_eeprom = e100_get_eeprom, + .set_eeprom = e100_set_eeprom, + .get_ringparam = e100_get_ringparam, + .set_ringparam = e100_set_ringparam, + .self_test_count = e100_diag_test_count, + .self_test = e100_diag_test, + .get_strings = e100_get_strings, + .phys_id = e100_phys_id, + .get_stats_count = e100_get_stats_count, + .get_ethtool_stats = e100_get_ethtool_stats, +}; + +static int e100_do_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd) +{ + struct nic *nic = netdev->priv; + struct mii_ioctl_data *mii = (struct mii_ioctl_data *)&ifr->ifr_data; + + return generic_mii_ioctl(&nic->mii, mii, cmd, NULL); +} + +static int e100_alloc(struct nic *nic) +{ + nic->mem = pci_alloc_consistent(nic->pdev, sizeof(struct mem), + &nic->dma_addr); + return nic->mem ? 0 : -ENOMEM; +} + +static void e100_free(struct nic *nic) +{ + if(nic->mem) { + pci_free_consistent(nic->pdev, sizeof(struct mem), + nic->mem, nic->dma_addr); + nic->mem = NULL; + } +} + +static int e100_open(struct net_device *netdev) +{ + struct nic *nic = netdev->priv; + int err = 0; + + netif_carrier_off(netdev); + if((err = e100_up(nic))) + DPRINTK(IFUP, ERR, "Cannot open interface, aborting.\n"); + return err; +} + +static int e100_close(struct net_device *netdev) +{ + e100_down(netdev->priv); + return 0; +} + +static int __devinit e100_probe(struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + struct net_device *netdev; + struct nic *nic; + int err; + + if(!(netdev = alloc_etherdev(sizeof(struct nic)))) { + if(((1 << debug) - 1) & NETIF_MSG_PROBE) + printk(KERN_ERR PFX "Etherdev alloc failed, abort.\n"); + return -ENOMEM; + } + + netdev->open = e100_open; + netdev->stop = e100_close; + netdev->hard_start_xmit = e100_xmit_frame; + netdev->get_stats = e100_get_stats; + netdev->set_multicast_list = e100_set_multicast_list; + netdev->set_mac_address = e100_set_mac_address; + netdev->change_mtu = e100_change_mtu; + netdev->do_ioctl = e100_do_ioctl; + SET_ETHTOOL_OPS(netdev, &e100_ethtool_ops); + netdev->tx_timeout = e100_tx_timeout; + netdev->watchdog_timeo = E100_WATCHDOG_PERIOD; +#ifdef CONFIG_E100_NAPI + netdev->poll = e100_poll; + netdev->weight = E100_NAPI_WEIGHT; +#endif +#ifdef CONFIG_NET_POLL_CONTROLLER + netdev->poll_controller = e100_netpoll; +#endif + + nic = netdev->priv; + nic->netdev = netdev; + nic->pdev = pdev; + nic->msg_enable = (1 << debug) - 1; + pci_set_drvdata(pdev, netdev); + + if((err = pci_enable_device(pdev))) { + DPRINTK(PROBE, ERR, "Cannot enable PCI device, aborting.\n"); + goto err_out_free_dev; + } + + if(!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) { + DPRINTK(PROBE, ERR, "Cannot find proper PCI device " + "base address, aborting.\n"); + err = -ENODEV; + goto err_out_disable_pdev; + } + + if((err = pci_request_regions(pdev, DRV_NAME))) { + DPRINTK(PROBE, ERR, "Cannot obtain PCI resources, aborting.\n"); + goto err_out_disable_pdev; + } + + pci_set_master(pdev); + + if((err = pci_set_dma_mask(pdev, 0xFFFFFFFFULL))) { + DPRINTK(PROBE, ERR, "No usable DMA configuration, aborting.\n"); + goto err_out_free_res; + } + + SET_MODULE_OWNER(netdev); + SET_NETDEV_DEV(netdev, &pdev->dev); + + nic->csr = ioremap(pci_resource_start(pdev, 0), sizeof(struct csr)); + if(!nic->csr) { + DPRINTK(PROBE, ERR, "Cannot map device registers, aborting.\n"); + err = -ENOMEM; + goto err_out_free_res; + } + + if(ent->driver_data) + nic->flags |= ich; + else + nic->flags &= ~ich; + + spin_lock_init(&nic->cb_lock); + spin_lock_init(&nic->cmd_lock); + + init_timer(&nic->watchdog); + nic->watchdog.function = e100_watchdog; + nic->watchdog.data = (unsigned long)nic; + init_timer(&nic->blink_timer); + nic->blink_timer.function = e100_blink_led; + nic->blink_timer.data = (unsigned long)nic; + + if((err = e100_alloc(nic))) { + DPRINTK(PROBE, ERR, "Cannot alloc driver memory, aborting.\n"); + goto err_out_iounmap; + } + + e100_get_defaults(nic); + e100_hw_reset(nic); + e100_phy_init(nic); + + if((err = e100_eeprom_load(nic))) + goto err_out_free; + ((u16 *)netdev->dev_addr)[0] = le16_to_cpu(nic->eeprom[0]); + ((u16 *)netdev->dev_addr)[1] = le16_to_cpu(nic->eeprom[1]); + ((u16 *)netdev->dev_addr)[2] = le16_to_cpu(nic->eeprom[2]); + if(!is_valid_ether_addr(netdev->dev_addr)) { + DPRINTK(PROBE, ERR, "Invalid MAC address from " + "EEPROM, aborting.\n"); + err = -EAGAIN; + goto err_out_free; + } + + /* Wol magic packet can be enabled from eeprom */ + if((nic->mac >= mac_82558_D101_A4) && + (nic->eeprom[eeprom_id] & eeprom_id_wol)) + nic->flags |= wol_magic; + + pci_enable_wake(pdev, 0, nic->flags & (wol_magic | e100_asf(nic))); + + if((err = register_netdev(netdev))) { + DPRINTK(PROBE, ERR, "Cannot register net device, aborting.\n"); + goto err_out_free; + } + + DPRINTK(PROBE, INFO, "addr 0x%lx, irq %d, " + "MAC addr %02X:%02X:%02X:%02X:%02X:%02X\n", + pci_resource_start(pdev, 0), pdev->irq, + netdev->dev_addr[0], netdev->dev_addr[1], netdev->dev_addr[2], + netdev->dev_addr[3], netdev->dev_addr[4], netdev->dev_addr[5]); + + return 0; + +err_out_free: + e100_free(nic); +err_out_iounmap: + iounmap(nic->csr); +err_out_free_res: + pci_release_regions(pdev); +err_out_disable_pdev: + pci_disable_device(pdev); +err_out_free_dev: + pci_set_drvdata(pdev, NULL); + free_netdev(netdev); + return err; +} + +static void __devexit e100_remove(struct pci_dev *pdev) +{ + struct net_device *netdev = pci_get_drvdata(pdev); + + if(netdev) { + struct nic *nic = netdev->priv; + unregister_netdev(netdev); + e100_free(nic); + iounmap(nic->csr); + free_netdev(netdev); + pci_release_regions(pdev); + pci_disable_device(pdev); + pci_set_drvdata(pdev, NULL); + } +} + +#ifdef CONFIG_PM +static int e100_suspend(struct pci_dev *pdev, u32 state) +{ + struct net_device *netdev = pci_get_drvdata(pdev); + struct nic *nic = netdev->priv; + + if(netif_running(netdev)) + e100_down(nic); + e100_hw_reset(nic); + netif_device_detach(netdev); + + pci_save_state(pdev, nic->pm_state); + pci_enable_wake(pdev, state, nic->flags & (wol_magic | e100_asf(nic))); + pci_disable_device(pdev); + pci_set_power_state(pdev, state); + + return 0; +} + +static int e100_resume(struct pci_dev *pdev) +{ + struct net_device *netdev = pci_get_drvdata(pdev); + struct nic *nic = netdev->priv; + + pci_set_power_state(pdev, 0); + pci_restore_state(pdev, nic->pm_state); + e100_hw_init(nic); + + netif_device_attach(netdev); + if(netif_running(netdev)) + e100_up(nic); + + return 0; +} +#endif + +static struct pci_driver e100_driver = { + .name = DRV_NAME, + .id_table = e100_id_table, + .probe = e100_probe, + .remove = __devexit_p(e100_remove), +#ifdef CONFIG_PM + .suspend = e100_suspend, + .resume = e100_resume, +#endif +}; + +static int __init e100_init_module(void) +{ + if(((1 << debug) - 1) & NETIF_MSG_DRV) { + printk(KERN_INFO PFX "%s, %s\n", DRV_DESCRIPTION, DRV_VERSION); + printk(KERN_INFO PFX "%s\n", DRV_COPYRIGHT); + } + return pci_module_init(&e100_driver); +} + +static void __exit e100_cleanup_module(void) +{ + pci_unregister_driver(&e100_driver); +} + +module_init(e100_init_module); +module_exit(e100_cleanup_module); diff -Nru a/drivers/net/e1000/e1000.h b/drivers/net/e1000/e1000.h --- a/drivers/net/e1000/e1000.h Thu Jan 22 18:59:23 2004 +++ b/drivers/net/e1000/e1000.h Thu Jan 22 18:59:23 2004 @@ -92,6 +92,16 @@ #define E1000_MAX_INTR 10 +/* How many descriptors for TX and RX ? */ +#define E1000_DEFAULT_TXD 256 +#define E1000_MAX_TXD 256 +#define E1000_MIN_TXD 80 +#define E1000_MAX_82544_TXD 4096 +#define E1000_DEFAULT_RXD 256 +#define E1000_MAX_RXD 256 +#define E1000_MIN_RXD 80 +#define E1000_MAX_82544_RXD 4096 + /* Supported Rx Buffer Sizes */ #define E1000_RXBUFFER_2048 2048 #define E1000_RXBUFFER_4096 4096 diff -Nru a/drivers/net/e1000/e1000_ethtool.c b/drivers/net/e1000/e1000_ethtool.c --- a/drivers/net/e1000/e1000_ethtool.c Thu Jan 22 18:59:25 2004 +++ b/drivers/net/e1000/e1000_ethtool.c Thu Jan 22 18:59:25 2004 @@ -39,6 +39,10 @@ extern void e1000_down(struct e1000_adapter *adapter); extern void e1000_reset(struct e1000_adapter *adapter); extern int e1000_set_spd_dplx(struct e1000_adapter *adapter, uint16_t spddplx); +extern int e1000_setup_rx_resources(struct e1000_adapter *adapter); +extern int e1000_setup_tx_resources(struct e1000_adapter *adapter); +extern void e1000_free_rx_resources(struct e1000_adapter *adapter); +extern void e1000_free_tx_resources(struct e1000_adapter *adapter); struct e1000_stats { char stat_string[ETH_GSTRING_LEN]; @@ -440,6 +444,71 @@ return ret_val; } +static int +e1000_ethtool_gring(struct e1000_adapter *adapter, + struct ethtool_ringparam *ring) +{ + e1000_mac_type mac_type = adapter->hw.mac_type; + struct e1000_desc_ring *txdr = &adapter->tx_ring; + struct e1000_desc_ring *rxdr = &adapter->rx_ring; + + ring->rx_max_pending = (mac_type < e1000_82544) ? E1000_MAX_RXD : + E1000_MAX_82544_RXD; + ring->tx_max_pending = (mac_type < e1000_82544) ? E1000_MAX_TXD : + E1000_MAX_82544_TXD; + ring->rx_mini_max_pending = 0; + ring->rx_jumbo_max_pending = 0; + ring->rx_pending = rxdr->count; + ring->tx_pending = txdr->count; + ring->rx_mini_pending = 0; + ring->rx_jumbo_pending = 0; + + return 0; +} +static int +e1000_ethtool_sring(struct e1000_adapter *adapter, + struct ethtool_ringparam *ring) +{ + int err; + e1000_mac_type mac_type = adapter->hw.mac_type; + struct e1000_desc_ring *txdr = &adapter->tx_ring; + struct e1000_desc_ring *rxdr = &adapter->rx_ring; + + if(netif_running(adapter->netdev)) { + e1000_down(adapter); + e1000_free_rx_resources(adapter); + e1000_free_tx_resources(adapter); + } + + rxdr->count = max(ring->rx_pending,(uint32_t)E1000_MIN_RXD); + rxdr->count = min(rxdr->count,(uint32_t)(mac_type < e1000_82544 ? + E1000_MAX_RXD : E1000_MAX_82544_RXD)); + E1000_ROUNDUP(rxdr->count, REQ_RX_DESCRIPTOR_MULTIPLE); + + txdr->count = max(ring->tx_pending,(uint32_t)E1000_MIN_TXD); + txdr->count = min(txdr->count,(uint32_t)(mac_type < e1000_82544 ? + E1000_MAX_TXD : E1000_MAX_82544_TXD)); + E1000_ROUNDUP(txdr->count, REQ_TX_DESCRIPTOR_MULTIPLE); + + if(netif_running(adapter->netdev)) { + if((err = e1000_setup_rx_resources(adapter))) + goto err_setup_rx; + if((err = e1000_setup_tx_resources(adapter))) + goto err_setup_tx; + if((err = e1000_up(adapter))) + goto err_up; + } + + return 0; +err_up: + e1000_free_tx_resources(adapter); +err_setup_tx: + e1000_free_rx_resources(adapter); +err_setup_rx: + e1000_reset(adapter); + return err; +} + #define REG_PATTERN_TEST(R, M, W) \ { \ uint32_t pat, value; \ @@ -579,8 +648,8 @@ *data = 0; /* Hook up test interrupt handler just for this test */ - if(request_irq - (netdev->irq, &e1000_test_intr, SA_SHIRQ, netdev->name, netdev)) { + if(request_irq(adapter->pdev->irq, &e1000_test_intr, SA_SHIRQ, + netdev->name, netdev)) { *data = 1; return -1; } @@ -664,7 +733,7 @@ msec_delay(10); /* Unhook test interrupt handler */ - free_irq(netdev->irq, netdev); + free_irq(adapter->pdev->irq, netdev); return *data; } @@ -770,9 +839,9 @@ PCI_DMA_TODEVICE); tx_desc->buffer_addr = cpu_to_le64(txdr->buffer_info[i].dma); tx_desc->lower.data = cpu_to_le32(skb->len); - tx_desc->lower.data |= E1000_TXD_CMD_EOP; - tx_desc->lower.data |= E1000_TXD_CMD_IFCS; - tx_desc->lower.data |= E1000_TXD_CMD_RPS; + tx_desc->lower.data |= cpu_to_le32(E1000_TXD_CMD_EOP | + E1000_TXD_CMD_IFCS | + E1000_TXD_CMD_RPS); tx_desc->upper.data = 0; } @@ -1501,6 +1570,19 @@ addr += offsetof(struct ethtool_eeprom, data); return e1000_ethtool_seeprom(adapter, &eeprom, addr); + } + case ETHTOOL_GRINGPARAM: { + struct ethtool_ringparam ering = {ETHTOOL_GRINGPARAM}; + e1000_ethtool_gring(adapter, &ering); + if(copy_to_user(addr, &ering, sizeof(ering))) + return -EFAULT; + return 0; + } + case ETHTOOL_SRINGPARAM: { + struct ethtool_ringparam ering; + if(copy_from_user(&ering, addr, sizeof(ering))) + return -EFAULT; + return e1000_ethtool_sring(adapter, &ering); } case ETHTOOL_GPAUSEPARAM: { struct ethtool_pauseparam epause = {ETHTOOL_GPAUSEPARAM}; diff -Nru a/drivers/net/e1000/e1000_hw.c b/drivers/net/e1000/e1000_hw.c --- a/drivers/net/e1000/e1000_hw.c Thu Jan 22 18:59:26 2004 +++ b/drivers/net/e1000/e1000_hw.c Thu Jan 22 18:59:26 2004 @@ -96,8 +96,14 @@ hw->phy_type = e1000_phy_m88; break; case IGP01E1000_I_PHY_ID: - hw->phy_type = e1000_phy_igp; - break; + if(hw->mac_type == e1000_82541 || + hw->mac_type == e1000_82541_rev_2 || + hw->mac_type == e1000_82547 || + hw->mac_type == e1000_82547_rev_2) { + hw->phy_type = e1000_phy_igp; + break; + } + /* Fall Through */ default: /* Should never have loaded on this device */ hw->phy_type = e1000_phy_undefined; @@ -148,7 +154,6 @@ e1000_write_phy_reg(hw, 0x0000, 0x3300); - if(hw->mac_type == e1000_82547) { uint16_t fused, fine, coarse; @@ -1485,8 +1490,8 @@ if(mii_status_reg & MII_SR_LINK_STATUS) break; msec_delay(100); } - if(i == 0) { /* We didn't get link */ - /* Reset the DSP and wait again for link. */ + if((i == 0) && (hw->phy_type == e1000_phy_m88)) { + /* We didn't get link. Reset the DSP and wait again for link. */ if((ret_val = e1000_phy_reset_dsp(hw))) { DEBUGOUT("Error Resetting PHY DSP\n"); return ret_val; @@ -1533,6 +1538,25 @@ phy_data))) return ret_val; + /* Polarity reversal workaround for forced 10F/10H links. */ + if(hw->mac_type <= e1000_82544 && + (hw->forced_speed_duplex == e1000_10_full || + hw->forced_speed_duplex == e1000_10_half)) { + if((ret_val = e1000_write_phy_reg(hw, M88E1000_PHY_PAGE_SELECT, + 0x0019))) + return ret_val; + if((ret_val = e1000_write_phy_reg(hw, M88E1000_PHY_GEN_CONTROL, + 0x8F0F))) + return ret_val; + /* IEEE requirement is 150ms */ + msec_delay(200); + if((ret_val = e1000_write_phy_reg(hw, M88E1000_PHY_PAGE_SELECT, + 0x0019))) + return ret_val; + if((ret_val = e1000_write_phy_reg(hw, M88E1000_PHY_GEN_CONTROL, + 0x8F00))) + return ret_val; + } } return E1000_SUCCESS; } @@ -1916,7 +1940,6 @@ uint32_t signal = 0; int32_t ret_val; uint16_t phy_data; - uint16_t lp_capability; DEBUGFUNC("e1000_check_for_link"); @@ -1996,24 +2019,17 @@ /* At this point we know that we are on copper and we have * auto-negotiated link. These are conditions for checking the link - * parter capability register. We use the link partner capability to - * determine if TBI Compatibility needs to be turned on or off. If - * the link partner advertises any speed in addition to Gigabit, then - * we assume that they are GMII-based, and TBI compatibility is not - * needed. If no other speeds are advertised, we assume the link - * partner is TBI-based, and we turn on TBI Compatibility. - */ - if(hw->tbi_compatibility_en) { - if((ret_val = e1000_read_phy_reg(hw, PHY_LP_ABILITY, - &lp_capability))) - return ret_val; - if(lp_capability & (NWAY_LPAR_10T_HD_CAPS | - NWAY_LPAR_10T_FD_CAPS | - NWAY_LPAR_100TX_HD_CAPS | - NWAY_LPAR_100TX_FD_CAPS | - NWAY_LPAR_100T4_CAPS)) { - /* If our link partner advertises anything in addition to - * gigabit, we do not need to enable TBI compatibility. + * partner capability register. We use the link speed to determine if + * TBI compatibility needs to be turned on or off. If the link is not + * at gigabit speed, then TBI compatibility is not needed. If we are + * at gigabit speed, we turn on TBI compatibility. + */ + if(hw->tbi_compatibility_en) { + uint16_t speed, duplex; + e1000_get_speed_and_duplex(hw, &speed, &duplex); + if(speed != SPEED_1000) { + /* If link speed is not set to gigabit speed, we do not need + * to enable TBI compatibility. */ if(hw->tbi_compatibility_on) { /* If we previously were in the mode, turn it off. */ @@ -2081,6 +2097,29 @@ DEBUGOUT("RXing /C/, enable AutoNeg and stop forcing link.\r\n"); E1000_WRITE_REG(hw, TXCW, hw->txcw); E1000_WRITE_REG(hw, CTRL, (ctrl & ~E1000_CTRL_SLU)); + + hw->serdes_link_down = FALSE; + } + /* If we force link for non-auto-negotiation switch, check link status + * based on MAC synchronization for internal serdes media type. + */ + else if((hw->media_type == e1000_media_type_internal_serdes) && + !(E1000_TXCW_ANE & E1000_READ_REG(hw, TXCW))) { + /* SYNCH bit and IV bit are sticky. */ + udelay(10); + if(E1000_RXCW_SYNCH & E1000_READ_REG(hw, RXCW)) { + if(!(rxcw & E1000_RXCW_IV)) { + hw->serdes_link_down = FALSE; + DEBUGOUT("SERDES: Link is up.\n"); + } + } else { + hw->serdes_link_down = TRUE; + DEBUGOUT("SERDES: Link is down.\n"); + } + } + if((hw->media_type == e1000_media_type_internal_serdes) && + (E1000_TXCW_ANE & E1000_READ_REG(hw, TXCW))) { + hw->serdes_link_down = !(E1000_STATUS_LU & E1000_READ_REG(hw, STATUS)); } return E1000_SUCCESS; } @@ -2481,8 +2520,8 @@ E1000_WRITE_REG(hw, MDIC, mdic); /* Poll the ready bit to see if the MDI read completed */ - for(i = 0; i < 64; i++) { - udelay(50); + for(i = 0; i < 640; i++) { + udelay(5); mdic = E1000_READ_REG(hw, MDIC); if(mdic & E1000_MDIC_READY) break; } @@ -3498,10 +3537,12 @@ if (e1000_acquire_eeprom(hw) != E1000_SUCCESS) return -E1000_ERR_EEPROM; - if(eeprom->type == e1000_eeprom_microwire) + if(eeprom->type == e1000_eeprom_microwire) { status = e1000_write_eeprom_microwire(hw, offset, words, data); - else + } else { status = e1000_write_eeprom_spi(hw, offset, words, data); + msec_delay(10); + } /* Done with writing */ e1000_release_eeprom(hw); @@ -3719,12 +3760,9 @@ hw->perm_mac_addr[i+1] = (uint8_t) (eeprom_data >> 8); } if(((hw->mac_type == e1000_82546) || (hw->mac_type == e1000_82546_rev_3)) && - (E1000_READ_REG(hw, STATUS) & E1000_STATUS_FUNC_1)) { - if(hw->perm_mac_addr[5] & 0x01) - hw->perm_mac_addr[5] &= ~(0x01); - else - hw->perm_mac_addr[5] |= 0x01; - } + (E1000_READ_REG(hw, STATUS) & E1000_STATUS_FUNC_1)) + hw->perm_mac_addr[5] ^= 0x01; + for(i = 0; i < NODE_ADDRESS_SIZE; i++) hw->mac_addr[i] = hw->perm_mac_addr[i]; return E1000_SUCCESS; @@ -3743,22 +3781,13 @@ e1000_init_rx_addrs(struct e1000_hw *hw) { uint32_t i; - uint32_t addr_low; - uint32_t addr_high; DEBUGFUNC("e1000_init_rx_addrs"); /* Setup the receive address. */ DEBUGOUT("Programming MAC Address into RAR[0]\n"); - addr_low = (hw->mac_addr[0] | - (hw->mac_addr[1] << 8) | - (hw->mac_addr[2] << 16) | (hw->mac_addr[3] << 24)); - - addr_high = (hw->mac_addr[4] | - (hw->mac_addr[5] << 8) | E1000_RAH_AV); - E1000_WRITE_REG_ARRAY(hw, RA, 0, addr_low); - E1000_WRITE_REG_ARRAY(hw, RA, 1, addr_high); + e1000_rar_set(hw, hw->mac_addr, 0); /* Zero out the other 15 receive addresses. */ DEBUGOUT("Clearing RAR[1-15]\n"); @@ -3775,6 +3804,7 @@ * mc_addr_list - the list of new multicast addresses * mc_addr_count - number of addresses * pad - number of bytes between addresses in the list + * rar_used_count - offset where to start adding mc addresses into the RAR's * * The given list replaces any existing list. Clears the last 15 receive * address registers and the multicast table. Uses receive address registers @@ -3785,11 +3815,11 @@ e1000_mc_addr_list_update(struct e1000_hw *hw, uint8_t *mc_addr_list, uint32_t mc_addr_count, - uint32_t pad) + uint32_t pad, + uint32_t rar_used_count) { uint32_t hash_value; uint32_t i; - uint32_t rar_used_count = 1; /* RAR[0] is used for our MAC address */ DEBUGFUNC("e1000_mc_addr_list_update"); @@ -4523,8 +4553,8 @@ e1000_read_reg_io(struct e1000_hw *hw, uint32_t offset) { - uint32_t io_addr = hw->io_base; - uint32_t io_data = hw->io_base + 4; + unsigned long io_addr = hw->io_base; + unsigned long io_data = hw->io_base + 4; e1000_io_write(hw, io_addr, offset); return e1000_io_read(hw, io_data); @@ -4543,8 +4573,8 @@ uint32_t offset, uint32_t value) { - uint32_t io_addr = hw->io_base; - uint32_t io_data = hw->io_base + 4; + unsigned long io_addr = hw->io_base; + unsigned long io_data = hw->io_base + 4; e1000_io_write(hw, io_addr, offset); e1000_io_write(hw, io_data, value); diff -Nru a/drivers/net/e1000/e1000_hw.h b/drivers/net/e1000/e1000_hw.h --- a/drivers/net/e1000/e1000_hw.h Thu Jan 22 18:59:26 2004 +++ b/drivers/net/e1000/e1000_hw.h Thu Jan 22 18:59:26 2004 @@ -291,7 +291,7 @@ /* Filters (multicast, vlan, receive) */ void e1000_init_rx_addrs(struct e1000_hw *hw); -void e1000_mc_addr_list_update(struct e1000_hw *hw, uint8_t * mc_addr_list, uint32_t mc_addr_count, uint32_t pad); +void e1000_mc_addr_list_update(struct e1000_hw *hw, uint8_t * mc_addr_list, uint32_t mc_addr_count, uint32_t pad, uint32_t rar_used_count); uint32_t e1000_hash_mc_addr(struct e1000_hw *hw, uint8_t * mc_addr); void e1000_mta_set(struct e1000_hw *hw, uint32_t hash_value); void e1000_rar_set(struct e1000_hw *hw, uint8_t * mc_addr, uint32_t rar_index); @@ -317,9 +317,9 @@ void e1000_read_pci_cfg(struct e1000_hw *hw, uint32_t reg, uint16_t * value); void e1000_write_pci_cfg(struct e1000_hw *hw, uint32_t reg, uint16_t * value); /* Port I/O is only supported on 82544 and newer */ -uint32_t e1000_io_read(struct e1000_hw *hw, uint32_t port); +uint32_t e1000_io_read(struct e1000_hw *hw, unsigned long port); uint32_t e1000_read_reg_io(struct e1000_hw *hw, uint32_t offset); -void e1000_io_write(struct e1000_hw *hw, uint32_t port, uint32_t value); +void e1000_io_write(struct e1000_hw *hw, unsigned long port, uint32_t value); void e1000_write_reg_io(struct e1000_hw *hw, uint32_t offset, uint32_t value); int32_t e1000_config_dsp_after_link_change(struct e1000_hw *hw, boolean_t link_up); int32_t e1000_set_d3_lplu_state(struct e1000_hw *hw, boolean_t active); @@ -978,7 +978,7 @@ e1000_ms_type master_slave; e1000_ms_type original_master_slave; e1000_ffe_config ffe_config_state; - uint32_t io_base; + unsigned long io_base; uint32_t phy_id; uint32_t phy_revision; uint32_t phy_addr; @@ -1021,6 +1021,7 @@ boolean_t speed_downgraded; e1000_dsp_config dsp_config_state; boolean_t get_link_status; + boolean_t serdes_link_down; boolean_t tbi_compatibility_en; boolean_t tbi_compatibility_on; boolean_t phy_reset_disable; @@ -1310,6 +1311,7 @@ #define E1000_RCTL_DPF 0x00400000 /* discard pause frames */ #define E1000_RCTL_PMCF 0x00800000 /* pass MAC control frames */ #define E1000_RCTL_BSEX 0x02000000 /* Buffer size extension */ +#define E1000_RCTL_SECRC 0x04000000 /* Strip Ethernet CRC */ /* Receive Descriptor */ #define E1000_RDT_DELAY 0x0000ffff /* Delay timer (1=1024us) */ diff -Nru a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c --- a/drivers/net/e1000/e1000_main.c Thu Jan 22 18:59:24 2004 +++ b/drivers/net/e1000/e1000_main.c Thu Jan 22 18:59:24 2004 @@ -30,10 +30,20 @@ /* Change Log * - * 5.2.20 9/30/03 + * 5.2.27 12/14/03 + * o Added netpoll support. + * o Fixed endianess bug causing ethtool loopback diags to fail on ppc. + * o Use pdev->irq rather than netdev->irq in preparation for MSI support. + * o Report driver message on user override of InterruptThrottleRate + * module parameter. + * o Change I/O address storage from uint32_t to unsigned long. + * o Added ethtool RINGPARAM support. + * + * 5.2.22 10/15/03 * o Bug fix: SERDES devices might be connected to a back-plane * switch that doesn't support auto-neg, so add the capability - * to force 1000/Full. + * to force 1000/Full. Also, since forcing 1000/Full, sample + * RxSynchronize bit to detect link state. * o Bug fix: Flow control settings for hi/lo watermark didn't * consider changes in the Rx FIFO size, which could occur with * Jumbo Frames or with the reduced FIFO in 82547. @@ -42,29 +52,18 @@ * o Bug fix: hang under heavy Tx stress when running out of Tx * descriptors; wasn't clearing context descriptor when backing * out of send because of no-resource condition. + * o Bug fix: check netif_running in dev->poll so we don't have to + * hang in dev->close until all polls are finished. [Robert + * Ollson (robert.olsson@data.slu.se)]. + * o Revert TxDescriptor ring size back to 256 since change to 1024 + * wasn't accepted into the kernel. * * 5.2.16 8/8/03 - * o Added support for new controllers: 82545GM, 82546GB, 82541/7_B1 - * o Bug fix: reset h/w before first EEPROM read because we don't know - * who may have been messing with the device before we got there. - * [Dave Johnson (ddj -a-t- cascv.brown.edu)] - * o Bug fix: read the correct work from EEPROM to detect programmed - * WoL settings. - * o Bug fix: TSO would hang if space left in FIFO was being miscalculated - * when mss dropped without a correspoding drop in the DMA buffer size. - * o ASF for Fiber nics isn't supported. - * o Bug fix: Workaround added for potential hang with 82544 running in - * PCI-X if send buffer terminates within an evenly-aligned dword. - * o Feature: Add support for ethtool flow control setting. - * o Feature: Add support for ethtool TSO setting. - * o Feature: Increase default Tx Descriptor count to 1024 for >= 82544. - * - * 5.1.13 5/28/03 */ char e1000_driver_name[] = "e1000"; char e1000_driver_string[] = "Intel(R) PRO/1000 Network Driver"; -char e1000_driver_version[] = "5.2.20-k1"; +char e1000_driver_version[] = "5.2.27-k1"; char e1000_copyright[] = "Copyright (c) 1999-2003 Intel Corporation."; /* e1000_pci_tbl - PCI Device ID Table @@ -89,7 +88,6 @@ {0x8086, 0x1011, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {0x8086, 0x1012, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {0x8086, 0x1013, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0x8086, 0x1014, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {0x8086, 0x1015, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {0x8086, 0x1016, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {0x8086, 0x1017, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, @@ -113,12 +111,16 @@ MODULE_DEVICE_TABLE(pci, e1000_pci_tbl); -/* Local Function Prototypes */ - int e1000_up(struct e1000_adapter *adapter); void e1000_down(struct e1000_adapter *adapter); void e1000_reset(struct e1000_adapter *adapter); int e1000_set_spd_dplx(struct e1000_adapter *adapter, uint16_t spddplx); +int e1000_setup_tx_resources(struct e1000_adapter *adapter); +int e1000_setup_rx_resources(struct e1000_adapter *adapter); +void e1000_free_tx_resources(struct e1000_adapter *adapter); +void e1000_free_rx_resources(struct e1000_adapter *adapter); + +/* Local Function Prototypes */ static int e1000_init_module(void); static void e1000_exit_module(void); @@ -127,15 +129,11 @@ static int e1000_sw_init(struct e1000_adapter *adapter); static int e1000_open(struct net_device *netdev); static int e1000_close(struct net_device *netdev); -static int e1000_setup_tx_resources(struct e1000_adapter *adapter); -static int e1000_setup_rx_resources(struct e1000_adapter *adapter); static void e1000_configure_tx(struct e1000_adapter *adapter); static void e1000_configure_rx(struct e1000_adapter *adapter); static void e1000_setup_rctl(struct e1000_adapter *adapter); static void e1000_clean_tx_ring(struct e1000_adapter *adapter); static void e1000_clean_rx_ring(struct e1000_adapter *adapter); -static void e1000_free_tx_resources(struct e1000_adapter *adapter); -static void e1000_free_rx_resources(struct e1000_adapter *adapter); static void e1000_set_multi(struct net_device *netdev); static void e1000_update_phy_info(unsigned long data); static void e1000_watchdog(unsigned long data); @@ -182,6 +180,11 @@ static int e1000_resume(struct pci_dev *pdev); #endif +#ifdef CONFIG_NET_POLL_CONTROLLER +/* for netdump / net console */ +static void e1000_netpoll (struct net_device *dev); +#endif + struct notifier_block e1000_notifier_reboot = { .notifier_call = e1000_notify_reboot, .next = NULL, @@ -268,7 +271,7 @@ e1000_configure_rx(adapter); e1000_alloc_rx_buffers(adapter); - if((err = request_irq(netdev->irq, &e1000_intr, + if((err = request_irq(adapter->pdev->irq, &e1000_intr, SA_SHIRQ | SA_SAMPLE_RANDOM, netdev->name, netdev))) return err; @@ -285,7 +288,7 @@ struct net_device *netdev = adapter->netdev; e1000_irq_disable(adapter); - free_irq(netdev->irq, netdev); + free_irq(adapter->pdev->irq, netdev); del_timer_sync(&adapter->tx_fifo_stall_timer); del_timer_sync(&adapter->watchdog_timer); del_timer_sync(&adapter->phy_info_timer); @@ -434,8 +437,10 @@ netdev->vlan_rx_register = e1000_vlan_rx_register; netdev->vlan_rx_add_vid = e1000_vlan_rx_add_vid; netdev->vlan_rx_kill_vid = e1000_vlan_rx_kill_vid; +#ifdef CONFIG_NET_POLL_CONTROLLER + netdev->poll_controller = e1000_netpoll; +#endif - netdev->irq = pdev->irq; netdev->mem_start = mmio_start; netdev->mem_end = mmio_start + mmio_len; netdev->base_addr = adapter->hw.io_base; @@ -749,7 +754,7 @@ * Return 0 on success, negative on failure **/ -static int +int e1000_setup_tx_resources(struct e1000_adapter *adapter) { struct e1000_desc_ring *txdr = &adapter->tx_ring; @@ -866,7 +871,7 @@ * Returns 0 on success, negative on failure **/ -static int +int e1000_setup_rx_resources(struct e1000_adapter *adapter) { struct e1000_desc_ring *rxdr = &adapter->rx_ring; @@ -1005,7 +1010,7 @@ * Free all transmit software resources **/ -static void +void e1000_free_tx_resources(struct e1000_adapter *adapter) { struct pci_dev *pdev = adapter->pdev; @@ -1073,7 +1078,7 @@ * Free all receive software resources **/ -static void +void e1000_free_rx_resources(struct e1000_adapter *adapter) { struct e1000_desc_ring *rx_ring = &adapter->rx_ring; @@ -1281,41 +1286,6 @@ e1000_leave_82542_rst(adapter); } -static void -e1000_tx_flush(struct e1000_adapter *adapter) -{ - uint32_t ctrl, tctl, txcw, icr; - - e1000_irq_disable(adapter); - - if(adapter->hw.mac_type < e1000_82543) { - /* Transmit Unit Reset */ - tctl = E1000_READ_REG(&adapter->hw, TCTL); - E1000_WRITE_REG(&adapter->hw, TCTL, tctl | E1000_TCTL_RST); - E1000_WRITE_REG(&adapter->hw, TCTL, tctl); - e1000_clean_tx_ring(adapter); - e1000_configure_tx(adapter); - } else { - txcw = E1000_READ_REG(&adapter->hw, TXCW); - E1000_WRITE_REG(&adapter->hw, TXCW, txcw & ~E1000_TXCW_ANE); - - ctrl = E1000_READ_REG(&adapter->hw, CTRL); - E1000_WRITE_REG(&adapter->hw, CTRL, ctrl | E1000_CTRL_SLU | - E1000_CTRL_ILOS); - - mdelay(10); - - e1000_clean_tx_irq(adapter); - E1000_WRITE_REG(&adapter->hw, CTRL, ctrl); - E1000_WRITE_REG(&adapter->hw, TXCW, txcw); - - /* clear the link status change interrupts this caused */ - icr = E1000_READ_REG(&adapter->hw, ICR); - } - - e1000_irq_enable(adapter); -} - /* need to wait a few seconds after link up to get diagnostic information from the phy */ static void @@ -1379,10 +1349,17 @@ struct net_device *netdev = adapter->netdev; struct e1000_desc_ring *txdr = &adapter->tx_ring; unsigned int i; + uint32_t link; e1000_check_for_link(&adapter->hw); - if(E1000_READ_REG(&adapter->hw, STATUS) & E1000_STATUS_LU) { + if((adapter->hw.media_type == e1000_media_type_internal_serdes) && + !(E1000_READ_REG(&adapter->hw, TXCW) & E1000_TXCW_ANE)) + link = !adapter->hw.serdes_link_down; + else + link = E1000_READ_REG(&adapter->hw, STATUS) & E1000_STATUS_LU; + + if(link) { if(!netif_carrier_ok(netdev)) { e1000_get_speed_and_duplex(&adapter->hw, &adapter->link_speed, @@ -1419,10 +1396,11 @@ if(!netif_carrier_ok(netdev)) { if(E1000_DESC_UNUSED(txdr) + 1 < txdr->count) { - unsigned long flags; - spin_lock_irqsave(&netdev->xmit_lock, flags); - e1000_tx_flush(adapter); - spin_unlock_irqrestore(&netdev->xmit_lock, flags); + /* We've lost link, so the controller stops DMA, + * but we've got queued Tx work that's never going + * to get done, so reset controller to flush Tx. + * (Do the reset outside of interrupt context). */ + schedule_work(&adapter->tx_timeout_task); } } @@ -2064,7 +2042,7 @@ atomic_inc(&adapter->irq_sem); E1000_WRITE_REG(&adapter->hw, IMC, ~0); E1000_WRITE_FLUSH(&adapter->hw); - synchronize_irq(adapter->netdev->irq); + synchronize_irq(adapter->pdev->irq); } /** @@ -2093,6 +2071,7 @@ { struct net_device *netdev = data; struct e1000_adapter *adapter = netdev->priv; + struct e1000_hw *hw = &adapter->hw; uint32_t icr = E1000_READ_REG(&adapter->hw, ICR); #ifndef CONFIG_E1000_NAPI unsigned int i; @@ -2102,7 +2081,7 @@ return IRQ_NONE; /* Not our interrupt */ if(icr & (E1000_ICR_RXSEQ | E1000_ICR_LSC)) { - adapter->hw.get_link_status = 1; + hw->get_link_status = 1; mod_timer(&adapter->watchdog_timer, jiffies); } @@ -2114,7 +2093,7 @@ */ atomic_inc(&adapter->irq_sem); - E1000_WRITE_REG(&adapter->hw, IMC, ~0); + E1000_WRITE_REG(hw, IMC, ~0); __netif_rx_schedule(netdev); } #else @@ -2146,7 +2125,7 @@ *budget -= work_done; netdev->quota -= work_done; - if(work_done < work_to_do) { + if(work_done < work_to_do || !netif_running(netdev)) { netif_rx_complete(netdev); e1000_irq_enable(adapter); } @@ -2642,13 +2621,13 @@ } uint32_t -e1000_io_read(struct e1000_hw *hw, uint32_t port) +e1000_io_read(struct e1000_hw *hw, unsigned long port) { return inl(port); } void -e1000_io_write(struct e1000_hw *hw, uint32_t port, uint32_t value) +e1000_io_write(struct e1000_hw *hw, unsigned long port, uint32_t value) { outl(value, port); } @@ -2897,6 +2876,22 @@ } return 0; +} +#endif + +#ifdef CONFIG_NET_POLL_CONTROLLER +/* + * Polling 'interrupt' - used by things like netconsole to send skbs + * without having to re-enable interrupts. It's not called while + * the interrupt routine is executing. + */ + +static void e1000_netpoll (struct net_device *dev) +{ + struct e1000_adapter *adapter = dev->priv; + disable_irq(adapter->pdev->irq); + e1000_intr (adapter->pdev->irq, dev, NULL); + enable_irq(adapter->pdev->irq); } #endif diff -Nru a/drivers/net/e1000/e1000_param.c b/drivers/net/e1000/e1000_param.c --- a/drivers/net/e1000/e1000_param.c Thu Jan 22 18:59:26 2004 +++ b/drivers/net/e1000/e1000_param.c Thu Jan 22 18:59:26 2004 @@ -196,16 +196,6 @@ #define AUTONEG_ADV_MASK 0x2F #define FLOW_CONTROL_DEFAULT FLOW_CONTROL_FULL -#define DEFAULT_TXD 256 -#define MAX_TXD 256 -#define MIN_TXD 80 -#define MAX_82544_TXD 4096 - -#define DEFAULT_RXD 256 -#define MAX_RXD 256 -#define MIN_RXD 80 -#define MAX_82544_RXD 4096 - #define DEFAULT_RDTR 0 #define MAX_RXDELAY 0xFFFF #define MIN_RXDELAY 0 @@ -320,14 +310,15 @@ struct e1000_option opt = { .type = range_option, .name = "Transmit Descriptors", - .err = "using default of " __MODULE_STRING(DEFAULT_TXD), - .def = DEFAULT_TXD, - .arg = { .r = { .min = MIN_TXD }} + .err = "using default of " + __MODULE_STRING(E1000_DEFAULT_TXD), + .def = E1000_DEFAULT_TXD, + .arg = { .r = { .min = E1000_MIN_TXD }} }; struct e1000_desc_ring *tx_ring = &adapter->tx_ring; e1000_mac_type mac_type = adapter->hw.mac_type; opt.arg.r.max = mac_type < e1000_82544 ? - MAX_TXD : MAX_82544_TXD; + E1000_MAX_TXD : E1000_MAX_82544_TXD; tx_ring->count = TxDescriptors[bd]; e1000_validate_option(&tx_ring->count, &opt); @@ -337,13 +328,15 @@ struct e1000_option opt = { .type = range_option, .name = "Receive Descriptors", - .err = "using default of " __MODULE_STRING(DEFAULT_RXD), - .def = DEFAULT_RXD, - .arg = { .r = { .min = MIN_RXD }} + .err = "using default of " + __MODULE_STRING(E1000_DEFAULT_RXD), + .def = E1000_DEFAULT_RXD, + .arg = { .r = { .min = E1000_MIN_RXD }} }; struct e1000_desc_ring *rx_ring = &adapter->rx_ring; e1000_mac_type mac_type = adapter->hw.mac_type; - opt.arg.r.max = mac_type < e1000_82544 ? MAX_RXD : MAX_82544_RXD; + opt.arg.r.max = mac_type < e1000_82544 ? E1000_MAX_RXD : + E1000_MAX_82544_RXD; rx_ring->count = RxDescriptors[bd]; e1000_validate_option(&rx_ring->count, &opt); @@ -446,13 +439,19 @@ }; adapter->itr = InterruptThrottleRate[bd]; - if(adapter->itr == 0) { - printk(KERN_INFO "%s turned off\n", opt.name); - } else if(adapter->itr == 1 || adapter->itr == -1) { - /* Dynamic mode */ + switch(adapter->itr) { + case -1: adapter->itr = 1; - } else { + break; + case 0: + printk(KERN_INFO "%s turned off\n", opt.name); + break; + case 1: + printk(KERN_INFO "%s set to dynamic mode\n", opt.name); + break; + default: e1000_validate_option(&adapter->itr, &opt); + break; } } diff -Nru a/drivers/net/e2100.c b/drivers/net/e2100.c --- a/drivers/net/e2100.c Thu Jan 22 18:59:26 2004 +++ b/drivers/net/e2100.c Thu Jan 22 18:59:26 2004 @@ -95,7 +95,6 @@ #define E21_BIG_RX_STOP_PG 0xF0 /* Last page +1 of RX ring */ #define E21_TX_START_PG E21_RX_STOP_PG /* First page of TX buffer */ -int e2100_probe(struct net_device *dev); static int e21_probe1(struct net_device *dev, int ioaddr); static int e21_open(struct net_device *dev); @@ -117,10 +116,11 @@ station address). */ -int __init e2100_probe(struct net_device *dev) +static int __init do_e2100_probe(struct net_device *dev) { int *port; int base_addr = dev->base_addr; + int irq = dev->irq; SET_MODULE_OWNER(dev); @@ -129,13 +129,46 @@ else if (base_addr != 0) /* Don't probe at all. */ return -ENXIO; - for (port = e21_probe_list; *port; port++) + for (port = e21_probe_list; *port; port++) { + dev->irq = irq; if (e21_probe1(dev, *port) == 0) return 0; + } return -ENODEV; } +static void cleanup_card(struct net_device *dev) +{ + /* NB: e21_close() handles free_irq */ + release_region(dev->base_addr, E21_IO_EXTENT); +} + +struct net_device * __init e2100_probe(int unit) +{ + struct net_device *dev = alloc_ei_netdev(); + int err; + + if (!dev) + return ERR_PTR(-ENOMEM); + + sprintf(dev->name, "eth%d", unit); + netdev_boot_setup_check(dev); + + err = do_e2100_probe(dev); + if (err) + goto out; + err = register_netdev(dev); + if (err) + goto out1; + return dev; +out1: + cleanup_card(dev); +out: + free_netdev(dev); + return ERR_PTR(err); +} + static int __init e21_probe1(struct net_device *dev, int ioaddr) { int i, status, retval; @@ -175,13 +208,6 @@ for (i = 0; i < 6; i++) printk(" %02X", station_addr[i]); - /* Allocate dev->priv and fill in 8390 specific dev fields. */ - if (ethdev_init(dev)) { - printk (" unable to get memory for dev->priv.\n"); - retval = -ENOMEM; - goto out; - } - if (dev->irq < 2) { int irqlist[] = {15,11,10,12,5,9,3,4}, i; for (i = 0; i < 8; i++) @@ -191,8 +217,6 @@ } if (i >= 8) { printk(" unable to get IRQ %d.\n", dev->irq); - kfree(dev->priv); - dev->priv = NULL; retval = -EAGAIN; goto out; } @@ -245,6 +269,9 @@ ei_status.get_8390_hdr = &e21_get_8390_hdr; dev->open = &e21_open; dev->stop = &e21_close; +#ifdef CONFIG_NET_POLL_CONTROLLER + dev->poll_controller = ei_poll; +#endif NS8390_init(dev, 0); return 0; @@ -376,7 +403,7 @@ #ifdef MODULE #define MAX_E21_CARDS 4 /* Max number of E21 cards per module */ -static struct net_device dev_e21[MAX_E21_CARDS]; +static struct net_device *dev_e21[MAX_E21_CARDS]; static int io[MAX_E21_CARDS]; static int irq[MAX_E21_CARDS]; static int mem[MAX_E21_CARDS]; @@ -398,29 +425,35 @@ int init_module(void) { + struct net_device *dev; int this_dev, found = 0; for (this_dev = 0; this_dev < MAX_E21_CARDS; this_dev++) { - struct net_device *dev = &dev_e21[this_dev]; - dev->irq = irq[this_dev]; - dev->base_addr = io[this_dev]; - dev->mem_start = mem[this_dev]; - dev->mem_end = xcvr[this_dev]; /* low 4bits = xcvr sel. */ - dev->init = e2100_probe; if (io[this_dev] == 0) { if (this_dev != 0) break; /* only autoprobe 1st one */ printk(KERN_NOTICE "e2100.c: Presently autoprobing (not recommended) for a single card.\n"); } - if (register_netdev(dev) != 0) { - printk(KERN_WARNING "e2100.c: No E2100 card found (i/o = 0x%x).\n", io[this_dev]); - if (found != 0) { /* Got at least one. */ - return 0; + dev = alloc_ei_netdev(); + if (!dev) + break; + dev->irq = irq[this_dev]; + dev->base_addr = io[this_dev]; + dev->mem_start = mem[this_dev]; + dev->mem_end = xcvr[this_dev]; /* low 4bits = xcvr sel. */ + if (do_e2100_probe(dev) == 0) { + if (register_netdev(dev) == 0) { + dev_e21[found++] = dev; + continue; } - return -ENXIO; + cleanup_card(dev); } - found++; + free_netdev(dev); + printk(KERN_WARNING "e2100.c: No E2100 card found (i/o = 0x%x).\n", io[this_dev]); + break; } - return 0; + if (found) + return 0; + return -ENXIO; } void @@ -429,13 +462,11 @@ int this_dev; for (this_dev = 0; this_dev < MAX_E21_CARDS; this_dev++) { - struct net_device *dev = &dev_e21[this_dev]; - if (dev->priv != NULL) { - void *priv = dev->priv; - /* NB: e21_close() handles free_irq */ - release_region(dev->base_addr, E21_IO_EXTENT); + struct net_device *dev = dev_e21[this_dev]; + if (dev) { unregister_netdev(dev); - kfree(priv); + cleanup_card(dev); + free_netdev(dev); } } } diff -Nru a/drivers/net/eepro.c b/drivers/net/eepro.c --- a/drivers/net/eepro.c Thu Jan 22 18:59:26 2004 +++ b/drivers/net/eepro.c Thu Jan 22 18:59:26 2004 @@ -302,9 +302,7 @@ /* Index to functions, as function prototypes. */ -extern int eepro_probe(struct net_device *dev); - -static int eepro_probe1(struct net_device *dev, short ioaddr); +static int eepro_probe1(struct net_device *dev, int autoprobe); static int eepro_open(struct net_device *dev); static int eepro_send_packet(struct sk_buff *skb, struct net_device *dev); static irqreturn_t eepro_interrupt(int irq, void *dev_id, struct pt_regs *regs); @@ -527,10 +525,11 @@ If dev->base_addr == 2, allocate space for the device and return success (detachable devices only). */ -int __init eepro_probe(struct net_device *dev) +static int __init do_eepro_probe(struct net_device *dev) { int i; int base_addr = dev->base_addr; + int irq = dev->irq; SET_MODULE_OWNER(dev); @@ -563,24 +562,48 @@ #endif if (base_addr > 0x1ff) /* Check a single specified location. */ - return eepro_probe1(dev, base_addr); + return eepro_probe1(dev, 0); else if (base_addr != 0) /* Don't probe at all. */ return -ENXIO; - for (i = 0; eepro_portlist[i]; i++) { - int ioaddr = eepro_portlist[i]; - - if (check_region(ioaddr, EEPRO_IO_EXTENT)) - continue; - if (eepro_probe1(dev, ioaddr) == 0) + dev->base_addr = eepro_portlist[i]; + dev->irq = irq; + if (eepro_probe1(dev, 1) == 0) return 0; } return -ENODEV; } +struct net_device * __init eepro_probe(int unit) +{ + struct net_device *dev = alloc_etherdev(sizeof(struct eepro_local)); + int err; + + if (!dev) + return ERR_PTR(-ENODEV); + + SET_MODULE_OWNER(dev); + + sprintf(dev->name, "eth%d", unit); + netdev_boot_setup_check(dev); + + err = do_eepro_probe(dev); + if (err) + goto out; + err = register_netdev(dev); + if (err) + goto out1; + return dev; +out1: + release_region(dev->base_addr, EEPRO_IO_EXTENT); +out: + free_netdev(dev); + return ERR_PTR(err); +} + static void __init printEEPROMInfo(short ioaddr, struct net_device *dev) { unsigned short Word; @@ -713,83 +736,75 @@ probes on the ISA bus. A good device probe avoids doing writes, and verifies that the correct device exists and functions. */ -static int __init eepro_probe1(struct net_device *dev, short ioaddr) +static int __init eepro_probe1(struct net_device *dev, int autoprobe) { unsigned short station_addr[6], id, counter; - int i, j, irqMask, retval = 0; + int i; struct eepro_local *lp; enum iftype { AUI=0, BNC=1, TPE=2 }; + int ioaddr = dev->base_addr; + + /* Grab the region so we can find another board if autoIRQ fails. */ + if (!request_region(ioaddr, EEPRO_IO_EXTENT, dev->name)) { + if (!autoprobe) + printk(KERN_WARNING "EEPRO: io-port 0x%04x in use \n", + ioaddr); + return -EBUSY; + } /* Now, we are going to check for the signature of the ID_REG (register 2 of bank 0) */ - id=inb(ioaddr + ID_REG); + id = inb(ioaddr + ID_REG); - if (((id) & ID_REG_MASK) != ID_REG_SIG) { - retval = -ENODEV; + if ((id & ID_REG_MASK) != ID_REG_SIG) goto exit; - } - /* We seem to have the 82595 signature, let's - play with its counter (last 2 bits of - register 2 of bank 0) to be sure. */ + /* We seem to have the 82595 signature, let's + play with its counter (last 2 bits of + register 2 of bank 0) to be sure. */ - counter = (id & R_ROBIN_BITS); - - if (((id=inb(ioaddr+ID_REG)) & R_ROBIN_BITS)!=(counter + 0x40)) { - retval = -ENODEV; - goto exit; - } + counter = id & R_ROBIN_BITS; - /* Initialize the device structure */ - dev->priv = kmalloc(sizeof(struct eepro_local), GFP_KERNEL); - if (!dev->priv) { - retval = -ENOMEM; + if ((inb(ioaddr + ID_REG) & R_ROBIN_BITS) != (counter + 0x40)) goto exit; - } - - memset(dev->priv, 0, sizeof(struct eepro_local)); - - lp = (struct eepro_local *)dev->priv; - /* default values */ - lp->eepro = 0; + lp = (struct eepro_local *)dev->priv; + memset(lp, 0, sizeof(struct eepro_local)); lp->xmt_bar = XMT_BAR_PRO; lp->xmt_lower_limit_reg = XMT_LOWER_LIMIT_REG_PRO; lp->xmt_upper_limit_reg = XMT_UPPER_LIMIT_REG_PRO; lp->eeprom_reg = EEPROM_REG_PRO; + spin_lock_init(&lp->lock); - /* Now, get the ethernet hardware address from - the EEPROM */ - station_addr[0] = read_eeprom(ioaddr, 2, dev); - - /* FIXME - find another way to know that we've found - * an Etherexpress 10 - */ - if (station_addr[0] == 0x0000 || - station_addr[0] == 0xffff) { - lp->eepro = LAN595FX_10ISA; + /* Now, get the ethernet hardware address from + the EEPROM */ + station_addr[0] = read_eeprom(ioaddr, 2, dev); + + /* FIXME - find another way to know that we've found + * an Etherexpress 10 + */ + if (station_addr[0] == 0x0000 || station_addr[0] == 0xffff) { + lp->eepro = LAN595FX_10ISA; lp->eeprom_reg = EEPROM_REG_10; lp->xmt_lower_limit_reg = XMT_LOWER_LIMIT_REG_10; lp->xmt_upper_limit_reg = XMT_UPPER_LIMIT_REG_10; lp->xmt_bar = XMT_BAR_10; - station_addr[0] = read_eeprom(ioaddr, 2, dev); - } - station_addr[1] = read_eeprom(ioaddr, 3, dev); - station_addr[2] = read_eeprom(ioaddr, 4, dev); + station_addr[0] = read_eeprom(ioaddr, 2, dev); + } + station_addr[1] = read_eeprom(ioaddr, 3, dev); + station_addr[2] = read_eeprom(ioaddr, 4, dev); if (!lp->eepro) { if (read_eeprom(ioaddr,7,dev)== ee_FX_INT2IRQ) lp->eepro = 2; else if (station_addr[2] == SA_ADDR1) lp->eepro = 1; - } - - /* Fill in the 'dev' fields. */ - dev->base_addr = ioaddr; + } + /* Fill in the 'dev' fields. */ for (i=0; i < 6; i++) - dev->dev_addr[i] = ((unsigned char *) station_addr)[5-i]; + dev->dev_addr[i] = ((unsigned char *) station_addr)[5-i]; /* RX buffer must be more than 3K and less than 29K */ if (dev->mem_end < 3072 || dev->mem_end > 29696) @@ -798,65 +813,49 @@ /* calculate {xmt,rcv}_{lower,upper}_limit */ eepro_recalc(dev); - - if (GetBit( read_eeprom(ioaddr, 5, dev),ee_BNC_TPE)) - dev->if_port = BNC; + if (GetBit( read_eeprom(ioaddr, 5, dev),ee_BNC_TPE)) + dev->if_port = BNC; else dev->if_port = TPE; - if ((dev->irq < 2) && (lp->eepro!=0)) { - i = read_eeprom(ioaddr, 1, dev); - irqMask = read_eeprom(ioaddr, 7, dev); - i &= 0x07; /* Mask off INT number */ - - for (j=0; ((j<16) && (i>=0)); j++) { - if ((irqMask & (1<irq = j; - break; /* found bit corresponding to irq */ - } - i--; /* count bits set in irqMask */ - } - } - if (dev->irq < 2) { - printk(KERN_ERR " Duh! invalid interrupt vector stored in EEPROM.\n"); - retval = -ENODEV; - goto freeall; - } else - if (dev->irq==2) dev->irq = 9; - } - - /* Grab the region so we can find another board if autoIRQ fails. */ - if (!request_region(ioaddr, EEPRO_IO_EXTENT, dev->name)) { - printk(KERN_WARNING "EEPRO: io-port 0x%04x in use \n", ioaddr); - goto freeall; - } - ((struct eepro_local *)dev->priv)->lock = SPIN_LOCK_UNLOCKED; - - dev->open = eepro_open; - dev->stop = eepro_close; - dev->hard_start_xmit = eepro_send_packet; - dev->get_stats = eepro_get_stats; - dev->set_multicast_list = &set_multicast_list; - dev->tx_timeout = eepro_tx_timeout; - dev->watchdog_timeo = TX_TIMEOUT; - - /* Fill in the fields of the device structure with - ethernet generic values */ - ether_setup(dev); - + if (dev->irq < 2 && lp->eepro != 0) { + /* Mask off INT number */ + int count = read_eeprom(ioaddr, 1, dev) & 7; + unsigned irqMask = read_eeprom(ioaddr, 7, dev); + + while (count--) + irqMask &= irqMask - 1; + + count = ffs(irqMask); + + if (count) + dev->irq = count - 1; + + if (dev->irq < 2) { + printk(KERN_ERR " Duh! illegal interrupt vector stored in EEPROM.\n"); + goto exit; + } else if (dev->irq == 2) { + dev->irq = 9; + } + } + + dev->open = eepro_open; + dev->stop = eepro_close; + dev->hard_start_xmit = eepro_send_packet; + dev->get_stats = eepro_get_stats; + dev->set_multicast_list = &set_multicast_list; + dev->tx_timeout = eepro_tx_timeout; + dev->watchdog_timeo = TX_TIMEOUT; + /* print boot time info */ eepro_print_info(dev); /* reset 82595 */ - eepro_reset(ioaddr); - + eepro_reset(ioaddr); + return 0; exit: - return retval; -freeall: - kfree(dev->priv); - goto exit; - + release_region(dev->base_addr, EEPRO_IO_EXTENT); + return -ENODEV; } /* Open/initialize the board. This is called (in the current kernel) @@ -1701,7 +1700,7 @@ #ifdef MODULE #define MAX_EEPRO 8 -static struct net_device dev_eepro[MAX_EEPRO]; +static struct net_device *dev_eepro[MAX_EEPRO]; static int io[MAX_EEPRO]; static int irq[MAX_EEPRO]; @@ -1729,6 +1728,7 @@ int init_module(void) { + struct net_device *dev; int i; if (io[0] == 0 && autodetect == 0) { printk(KERN_WARNING "eepro_init_module: Probe is very dangerous in ISA boards!\n"); @@ -1743,17 +1743,24 @@ } for (i = 0; i < MAX_EEPRO; i++) { - struct net_device *d = &dev_eepro[n_eepro]; - d->mem_end = mem[i]; - d->base_addr = io[i]; - d->irq = irq[i]; - d->init = eepro_probe; - - if (register_netdev(d) == 0) - n_eepro++; - else - break; + dev = alloc_etherdev(sizeof(struct eepro_local)); + if (!dev) + break; + + dev->mem_end = mem[i]; + dev->base_addr = io[i]; + dev->irq = irq[i]; + + if (do_eepro_probe(dev) == 0) { + if (register_netdev(dev) == 0) { + dev_eepro[n_eepro++] = dev; + continue; + } + release_region(dev->base_addr, EEPRO_IO_EXTENT); } + free_netdev(dev); + break; + } if (n_eepro) printk(KERN_INFO "%s", version); @@ -1767,15 +1774,10 @@ int i; for (i=0; ipriv); - d->priv=NULL; - - /* If we don't do this, we can't re-insmod it later. */ - release_region(d->base_addr, EEPRO_IO_EXTENT); - + struct net_device *dev = dev_eepro[i]; + unregister_netdev(dev); + release_region(dev->base_addr, EEPRO_IO_EXTENT); + free_netdev(dev); } } #endif /* MODULE */ diff -Nru a/drivers/net/eepro100.c b/drivers/net/eepro100.c --- a/drivers/net/eepro100.c Thu Jan 22 18:59:26 2004 +++ b/drivers/net/eepro100.c Thu Jan 22 18:59:26 2004 @@ -542,6 +542,7 @@ static void speedo_refill_rx_buffers(struct net_device *dev, int force); static int speedo_rx(struct net_device *dev); static void speedo_tx_buffer_gc(struct net_device *dev); +static void poll_speedo (struct net_device *dev); static irqreturn_t speedo_interrupt(int irq, void *dev_instance, struct pt_regs *regs); static int speedo_close(struct net_device *dev); static struct net_device_stats *speedo_get_stats(struct net_device *dev); @@ -885,6 +886,9 @@ dev->get_stats = &speedo_get_stats; dev->set_multicast_list = &set_rx_mode; dev->do_ioctl = &speedo_ioctl; +#ifdef CONFIG_NET_POLL_CONTROLLER + dev->poll_controller = &poll_speedo; +#endif if (register_netdevice(dev)) goto err_free_unlock; @@ -1674,6 +1678,23 @@ clear_bit(0, (void*)&sp->in_interrupt); return IRQ_RETVAL(handled); } + +#ifdef CONFIG_NET_POLL_CONTROLLER +/* + * Polling 'interrupt' - used by things like netconsole to send skbs + * without having to re-enable interrupts. It's not called while + * the interrupt routine is executing. + */ + +static void poll_speedo (struct net_device *dev) +{ + /* disable_irq is not very nice, but with the funny lockless design + we have no other choice. */ + disable_irq(dev->irq); + speedo_interrupt (dev->irq, dev, NULL); + enable_irq(dev->irq); +} +#endif static inline struct RxFD *speedo_rx_alloc(struct net_device *dev, int entry) { diff -Nru a/drivers/net/eexpress.c b/drivers/net/eexpress.c --- a/drivers/net/eexpress.c Thu Jan 22 18:59:23 2004 +++ b/drivers/net/eexpress.c Thu Jan 22 18:59:23 2004 @@ -244,7 +244,6 @@ * Prototypes for Linux interface */ -extern int express_probe(struct net_device *dev); static int eexp_open(struct net_device *dev); static int eexp_close(struct net_device *dev); static void eexp_timeout(struct net_device *dev); @@ -334,11 +333,13 @@ * checks for presence of EtherExpress card */ -int __init express_probe(struct net_device *dev) +static int __init do_express_probe(struct net_device *dev) { unsigned short *port; static unsigned short ports[] = { 0x240,0x300,0x310,0x270,0x320,0x340,0 }; unsigned short ioaddr = dev->base_addr; + int dev_irq = dev->irq; + int err; SET_MODULE_OWNER(dev); @@ -391,27 +392,58 @@ } } #endif - if (ioaddr&0xfe00) - return eexp_hw_probe(dev,ioaddr); - else if (ioaddr) + if (ioaddr&0xfe00) { + if (!request_region(ioaddr, EEXP_IO_EXTENT, "EtherExpress")) + return -EBUSY; + err = eexp_hw_probe(dev,ioaddr); + release_region(ioaddr, EEXP_IO_EXTENT); + return err; + } else if (ioaddr) return -ENXIO; for (port=&ports[0] ; *port ; port++ ) { unsigned short sum = 0; int i; + if (!request_region(*port, EEXP_IO_EXTENT, "EtherExpress")) + continue; for ( i=0 ; i<4 ; i++ ) { unsigned short t; t = inb(*port + ID_PORT); sum |= (t>>4) << ((t & 0x03)<<2); } - if (sum==0xbaba && !eexp_hw_probe(dev,*port)) + if (sum==0xbaba && !eexp_hw_probe(dev,*port)) { + release_region(*port, EEXP_IO_EXTENT); return 0; + } + release_region(*port, EEXP_IO_EXTENT); + dev->irq = dev_irq; } return -ENODEV; } +struct net_device * __init express_probe(int unit) +{ + struct net_device *dev = alloc_etherdev(sizeof(struct net_local)); + int err; + + if (!dev) + return ERR_PTR(-ENOMEM); + + sprintf(dev->name, "eth%d", unit); + netdev_boot_setup_check(dev); + + err = do_express_probe(dev); + if (!err) { + err = register_netdev(dev); + if (!err) + return dev; + } + free_netdev(dev); + return ERR_PTR(err); +} + /* * open and initialize the adapter, ready for use */ @@ -1058,7 +1090,7 @@ unsigned int memory_size; int i; unsigned short xsum = 0; - struct net_local *lp; + struct net_local *lp = dev->priv; printk("%s: EtherExpress 16 at %#x ",dev->name,ioaddr); @@ -1108,17 +1140,18 @@ buswidth = !((setupval & 0x400) >> 10); } - dev->priv = lp = kmalloc(sizeof(struct net_local), GFP_KERNEL); - if (!dev->priv) - return -ENOMEM; - - memset(dev->priv, 0, sizeof(struct net_local)); + memset(lp, 0, sizeof(struct net_local)); spin_lock_init(&lp->lock); printk("(IRQ %d, %s connector, %d-bit bus", dev->irq, eexp_ifmap[dev->if_port], buswidth?8:16); + if (!request_region(dev->base_addr + 0x300e, 1, "EtherExpress")) + return -EBUSY; + eexp_hw_set_interface(dev); + + release_region(dev->base_addr + 0x300e, 1); /* Find out how much RAM we have on the card */ outw(0, dev->base_addr + WRITE_PTR); @@ -1156,7 +1189,6 @@ break; default: printk(") bad memory size (%dk).\n", memory_size); - kfree(dev->priv); return -ENODEV; break; } @@ -1171,7 +1203,6 @@ dev->set_multicast_list = &eexp_set_multicast; dev->tx_timeout = eexp_timeout; dev->watchdog_timeo = 2*HZ; - ether_setup(dev); return 0; } @@ -1654,7 +1685,7 @@ #define EEXP_MAX_CARDS 4 /* max number of cards to support */ -static struct net_device dev_eexp[EEXP_MAX_CARDS]; +static struct net_device *dev_eexp[EEXP_MAX_CARDS]; static int irq[EEXP_MAX_CARDS]; static int io[EEXP_MAX_CARDS]; @@ -1671,25 +1702,30 @@ */ int init_module(void) { + struct net_device *dev; int this_dev, found = 0; for (this_dev = 0; this_dev < EEXP_MAX_CARDS; this_dev++) { - struct net_device *dev = &dev_eexp[this_dev]; + dev = alloc_etherdev(sizeof(struct net_local)); dev->irq = irq[this_dev]; dev->base_addr = io[this_dev]; - dev->init = express_probe; if (io[this_dev] == 0) { - if (this_dev) break; + if (this_dev) + break; printk(KERN_NOTICE "eexpress.c: Module autoprobe not recommended, give io=xx.\n"); } - if (register_netdev(dev) != 0) { - printk(KERN_WARNING "eexpress.c: Failed to register card at 0x%x.\n", io[this_dev]); - if (found != 0) return 0; - return -ENXIO; + if (do_express_probe(dev) == 0 && register_netdev(dev) == 0) { + dev_eexp[this_dev] = dev; + found++; + continue; } - found++; + printk(KERN_WARNING "eexpress.c: Failed to register card at 0x%x.\n", io[this_dev]); + free_netdev(dev); + break; } - return 0; + if (found) + return 0; + return -ENXIO; } void cleanup_module(void) @@ -1697,11 +1733,10 @@ int this_dev; for (this_dev = 0; this_dev < EEXP_MAX_CARDS; this_dev++) { - struct net_device *dev = &dev_eexp[this_dev]; - if (dev->priv != NULL) { + struct net_device *dev = dev_eexp[this_dev]; + if (dev) { unregister_netdev(dev); - kfree(dev->priv); - dev->priv = NULL; + free_netdev(dev); } } } diff -Nru a/drivers/net/eql.c b/drivers/net/eql.c --- a/drivers/net/eql.c Thu Jan 22 18:59:26 2004 +++ b/drivers/net/eql.c Thu Jan 22 18:59:26 2004 @@ -600,7 +600,7 @@ err = register_netdev(dev_eql); if (err) - kfree(dev_eql); + free_netdev(dev_eql); return err; } diff -Nru a/drivers/net/es3210.c b/drivers/net/es3210.c --- a/drivers/net/es3210.c Thu Jan 22 18:59:26 2004 +++ b/drivers/net/es3210.c Thu Jan 22 18:59:26 2004 @@ -62,7 +62,6 @@ #include "8390.h" -int es_probe(struct net_device *dev); static int es_probe1(struct net_device *dev, int ioaddr); static int es_open(struct net_device *dev); @@ -125,9 +124,11 @@ * PROM for a match against the Racal-Interlan assigned value. */ -int __init es_probe(struct net_device *dev) +static int __init do_es_probe(struct net_device *dev) { unsigned short ioaddr = dev->base_addr; + int irq = dev->irq; + int mem_start = dev->mem_start; SET_MODULE_OWNER(dev); @@ -144,13 +145,47 @@ } /* EISA spec allows for up to 16 slots, but 8 is typical. */ - for (ioaddr = 0x1000; ioaddr < 0x9000; ioaddr += 0x1000) + for (ioaddr = 0x1000; ioaddr < 0x9000; ioaddr += 0x1000) { if (es_probe1(dev, ioaddr) == 0) return 0; + dev->irq = irq; + dev->mem_start = mem_start; + } return -ENODEV; } +static void cleanup_card(struct net_device *dev) +{ + free_irq(dev->irq, dev); + release_region(dev->base_addr, ES_IO_EXTENT); +} + +struct net_device * __init es_probe(int unit) +{ + struct net_device *dev = alloc_ei_netdev(); + int err; + + if (!dev) + return ERR_PTR(-ENOMEM); + + sprintf(dev->name, "eth%d", unit); + netdev_boot_setup_check(dev); + + err = do_es_probe(dev); + if (err) + goto out; + err = register_netdev(dev); + if (err) + goto out1; + return dev; +out1: + cleanup_card(dev); +out: + free_netdev(dev); + return ERR_PTR(err); +} + static int __init es_probe1(struct net_device *dev, int ioaddr) { int i, retval; @@ -240,13 +275,6 @@ printk("mem %#lx-%#lx\n", dev->mem_start, dev->mem_end-1); - /* Allocate dev->priv and fill in 8390 specific dev fields. */ - if (ethdev_init(dev)) { - printk (" unable to allocate memory for dev->priv.\n"); - retval = -ENOMEM; - goto out1; - } - #if ES_DEBUG & ES_D_PROBE if (inb(ioaddr + ES_CFG5)) printk("es3210: Warning - DMA channel enabled, but not used here.\n"); @@ -270,6 +298,9 @@ dev->open = &es_open; dev->stop = &es_close; +#ifdef CONFIG_NET_POLL_CONTROLLER + dev->poll_controller = ei_poll; +#endif NS8390_init(dev, 0); return 0; out1: @@ -376,7 +407,7 @@ #ifdef MODULE #define MAX_ES_CARDS 4 /* Max number of ES3210 cards per module */ #define NAMELEN 8 /* # of chars for storing dev->name */ -static struct net_device dev_es3210[MAX_ES_CARDS]; +static struct net_device *dev_es3210[MAX_ES_CARDS]; static int io[MAX_ES_CARDS]; static int irq[MAX_ES_CARDS]; static int mem[MAX_ES_CARDS]; @@ -393,26 +424,32 @@ int init_module(void) { + struct net_device *dev; int this_dev, found = 0; for (this_dev = 0; this_dev < MAX_ES_CARDS; this_dev++) { - struct net_device *dev = &dev_es3210[this_dev]; + if (io[this_dev] == 0 && this_dev != 0) + break; + dev = alloc_ei_netdev(); + if (!dev) + break; dev->irq = irq[this_dev]; dev->base_addr = io[this_dev]; - dev->mem_start = mem[this_dev]; /* Currently ignored by driver */ - dev->init = es_probe; - /* Default is to only install one card. */ - if (io[this_dev] == 0 && this_dev != 0) break; - if (register_netdev(dev) != 0) { - printk(KERN_WARNING "es3210.c: No es3210 card found (i/o = 0x%x).\n", io[this_dev]); - if (found != 0) { /* Got at least one. */ - return 0; + dev->mem_start = mem[this_dev]; + if (do_es_probe(dev) == 0) { + if (register_netdev(dev) == 0) { + dev_es3210[found++] = dev; + continue; } - return -ENXIO; + cleanup_card(dev); } - found++; + free_netdev(dev); + printk(KERN_WARNING "es3210.c: No es3210 card found (i/o = 0x%x).\n", io[this_dev]); + break; } - return 0; + if (found) + return 0; + return -ENXIO; } void @@ -421,13 +458,11 @@ int this_dev; for (this_dev = 0; this_dev < MAX_ES_CARDS; this_dev++) { - struct net_device *dev = &dev_es3210[this_dev]; - if (dev->priv != NULL) { - void *priv = dev->priv; - free_irq(dev->irq, dev); - release_region(dev->base_addr, ES_IO_EXTENT); + struct net_device *dev = dev_es3210[this_dev]; + if (dev) { unregister_netdev(dev); - kfree(priv); + cleanup_card(dev); + free_netdev(dev); } } } diff -Nru a/drivers/net/eth16i.c b/drivers/net/eth16i.c --- a/drivers/net/eth16i.c Thu Jan 22 18:59:26 2004 +++ b/drivers/net/eth16i.c Thu Jan 22 18:59:26 2004 @@ -369,7 +369,6 @@ #define NUM_OF_EISA_IRQS 8 static unsigned int eth16i_tx_buf_map[] = { 2048, 2048, 4096, 8192 }; -static unsigned int boot = 1; /* Use 0 for production, 1 for verification, >2 for debug */ #ifndef ETH16I_DEBUG @@ -395,8 +394,6 @@ /* Function prototypes */ -extern int eth16i_probe(struct net_device *dev); - static int eth16i_probe1(struct net_device *dev, int ioaddr); static int eth16i_check_signature(int ioaddr); static int eth16i_probe_port(int ioaddr); @@ -418,7 +415,7 @@ static void eth16i_skip_packet(struct net_device *dev); static void eth16i_multicast(struct net_device *dev); static void eth16i_select_regbank(unsigned char regbank, int ioaddr); -static void eth16i_initialize(struct net_device *dev); +static void eth16i_initialize(struct net_device *dev, int boot); #if 0 static int eth16i_set_irq(struct net_device *dev); @@ -432,7 +429,7 @@ static char cardname[] __initdata = "ICL EtherTeam 16i/32"; -int __init eth16i_probe(struct net_device *dev) +static int __init do_eth16i_probe(struct net_device *dev) { int i; int ioaddr; @@ -461,14 +458,38 @@ return -ENODEV; } +struct net_device * __init eth16i_probe(int unit) +{ + struct net_device *dev = alloc_etherdev(sizeof(struct eth16i_local)); + int err; + + if (!dev) + return ERR_PTR(-ENOMEM); + + sprintf(dev->name, "eth%d", unit); + netdev_boot_setup_check(dev); + + err = do_eth16i_probe(dev); + if (err) + goto out; + err = register_netdev(dev); + if (err) + goto out1; + return dev; +out1: + free_irq(dev->irq, dev); + release_region(dev->base_addr, ETH16I_IO_EXTENT); +out: + free_netdev(dev); + return ERR_PTR(err); +} + static int __init eth16i_probe1(struct net_device *dev, int ioaddr) { - struct eth16i_local *lp; + struct eth16i_local *lp = dev->priv; static unsigned version_printed; int retval; - boot = 1; /* To inform initilization that we are in boot probe */ - /* Let's grab the region */ if (!request_region(ioaddr, ETH16I_IO_EXTENT, dev->name)) return -EBUSY; @@ -531,22 +552,13 @@ eth16i_select_regbank(TRANSCEIVER_MODE_RB, ioaddr); outb(0x38, ioaddr + TRANSCEIVER_MODE_REG); - eth16i_initialize(dev); /* Initialize rest of the chip's registers */ + eth16i_initialize(dev, 1); /* Initialize rest of the chip's registers */ /* Now let's same some energy by shutting down the chip ;) */ BITCLR(ioaddr + CONFIG_REG_1, POWERUP); /* Initialize the device structure */ - if(dev->priv == NULL) { - dev->priv = kmalloc(sizeof(struct eth16i_local), GFP_KERNEL); - if(dev->priv == NULL) { - free_irq(dev->irq, dev); - retval = -ENOMEM; - goto out; - } - } - - memset(dev->priv, 0, sizeof(struct eth16i_local)); + memset(lp, 0, sizeof(struct eth16i_local)); dev->open = eth16i_open; dev->stop = eth16i_close; dev->hard_start_xmit = eth16i_tx; @@ -554,15 +566,7 @@ dev->set_multicast_list = eth16i_multicast; dev->tx_timeout = eth16i_timeout; dev->watchdog_timeo = TX_TIMEOUT; - - lp = (struct eth16i_local *)dev->priv; spin_lock_init(&lp->lock); - - /* Fill in the fields of the device structure with ethernet values. */ - ether_setup(dev); - - boot = 0; - return 0; out: release_region(ioaddr, ETH16I_IO_EXTENT); @@ -570,7 +574,7 @@ } -static void eth16i_initialize(struct net_device *dev) +static void eth16i_initialize(struct net_device *dev, int boot) { int ioaddr = dev->base_addr; int i, node_w = 0; @@ -953,7 +957,7 @@ outb(0xc0 | POWERUP, ioaddr + CONFIG_REG_1); /* Initialize the chip */ - eth16i_initialize(dev); + eth16i_initialize(dev, 0); /* Set the transmit buffer size */ lp->tx_buf_size = eth16i_tx_buf_map[ETH16I_TX_BUF_SIZE & 0x03]; @@ -1401,7 +1405,7 @@ #define MAX_ETH16I_CARDS 4 /* Max number of Eth16i cards per module */ -static struct net_device dev_eth16i[MAX_ETH16I_CARDS]; +static struct net_device *dev_eth16i[MAX_ETH16I_CARDS]; static int io[MAX_ETH16I_CARDS]; #if 0 static int irq[MAX_ETH16I_CARDS]; @@ -1431,14 +1435,14 @@ int init_module(void) { int this_dev, found = 0; + struct net_device *dev; + + for (this_dev = 0; this_dev < MAX_ETH16I_CARDS; this_dev++) { + dev = alloc_etherdev(sizeof(struct eth16i_local)); + if (!dev) + break; - for(this_dev = 0; this_dev < MAX_ETH16I_CARDS; this_dev++) - { - struct net_device *dev = &dev_eth16i[this_dev]; - - dev->irq = 0; /* irq[this_dev]; */ dev->base_addr = io[this_dev]; - dev->init = eth16i_probe; if(debug != -1) eth16i_debug = debug; @@ -1448,44 +1452,43 @@ dev->if_port = eth16i_parse_mediatype(mediatype[this_dev]); - if(io[this_dev] == 0) - { - if(this_dev != 0) break; /* Only autoprobe 1st one */ + if(io[this_dev] == 0) { + if(this_dev != 0) /* Only autoprobe 1st one */ + break; printk(KERN_NOTICE "eth16i.c: Presently autoprobing (not recommended) for a single card.\n"); } - if(register_netdev(dev) != 0) - { - printk(KERN_WARNING "eth16i.c No Eth16i card found (i/o = 0x%x).\n", - io[this_dev]); - - if(found != 0) return 0; - return -ENXIO; + if (do_eth16i_probe(dev) == 0) { + if (register_netdev(dev) == 0) { + dev_eth16i[found++] = dev; + continue; + } + free_irq(dev->irq, dev); + release_region(dev->base_addr, ETH16I_IO_EXTENT); } - - found++; + printk(KERN_WARNING "eth16i.c No Eth16i card found (i/o = 0x%x).\n", + io[this_dev]); + free_netdev(dev); + break; } - return 0; + if (found) + return 0; + return -ENXIO; } void cleanup_module(void) { int this_dev; - for(this_dev = 0; this_dev < MAX_ETH16I_CARDS; this_dev++) - { - struct net_device* dev = &dev_eth16i[this_dev]; + for(this_dev = 0; this_dev < MAX_ETH16I_CARDS; this_dev++) { + struct net_device *dev = dev_eth16i[this_dev]; - if(dev->priv != NULL) - { + if(dev->priv) { unregister_netdev(dev); - kfree(dev->priv); - dev->priv = NULL; - free_irq(dev->irq, dev); release_region(dev->base_addr, ETH16I_IO_EXTENT); - + free_netdev(dev); } } } diff -Nru a/drivers/net/ethertap.c b/drivers/net/ethertap.c --- a/drivers/net/ethertap.c Thu Jan 22 18:59:24 2004 +++ b/drivers/net/ethertap.c Thu Jan 22 18:59:24 2004 @@ -72,8 +72,7 @@ struct net_device *dev; int err = -ENOMEM; - dev = alloc_netdev(sizeof(struct net_local), "tap%d", - ether_setup); + dev = alloc_etherdev(sizeof(struct net_local)); if (!dev) goto out; diff -Nru a/drivers/net/ewrk3.c b/drivers/net/ewrk3.c --- a/drivers/net/ewrk3.c Thu Jan 22 18:59:27 2004 +++ b/drivers/net/ewrk3.c Thu Jan 22 18:59:27 2004 @@ -324,25 +324,14 @@ static int Write_EEPROM(short data, u_long iobase, u_char eaddr); static u_char get_hw_addr(struct net_device *dev, u_char * eeprom_image, char chipType); -static void isa_probe(struct net_device *dev, u_long iobase); -static void eisa_probe(struct net_device *dev, u_long iobase); -static struct net_device *alloc_device(struct net_device *dev, u_long iobase); -static int ewrk3_dev_index(char *s); -static struct net_device *insert_device(struct net_device *dev, u_long iobase, int (*init) (struct net_device *)); +static int ewrk3_probe1(struct net_device *dev, u_long iobase, int irq); +static int isa_probe(struct net_device *dev, u_long iobase); +static int eisa_probe(struct net_device *dev, u_long iobase); - -#ifdef MODULE -static int autoprobed = 1, loading_module = 1; - -#else -static u_char irq[] = -{5, 0, 10, 3, 11, 9, 15, 12}; -static int autoprobed, loading_module; - -#endif /* MODULE */ +static u_char irq[MAX_NUM_EWRK3S+1] = {5, 0, 10, 3, 11, 9, 15, 12}; static char name[EWRK3_STRLEN + 1]; -static int num_ewrk3s, num_eth; +static int num_ewrks3s; /* ** Miscellaneous defines... @@ -352,38 +341,50 @@ mdelay(1);\ } -int __init ewrk3_probe(struct net_device *dev) +struct net_device * __init ewrk3_probe(int unit) { - int tmp = num_ewrk3s, status = -ENODEV; - u_long iobase = dev->base_addr; + struct net_device *dev = alloc_etherdev(sizeof(struct ewrk3_private)); + int err; + + if (!dev) + return ERR_PTR(-ENOMEM); + if (unit >= 0) { + sprintf(dev->name, "eth%d", unit); + netdev_boot_setup_check(dev); + } SET_MODULE_OWNER(dev); - if ((iobase == 0) && loading_module) { - printk("Autoprobing is not supported when loading a module based driver.\n"); - status = -EIO; - } else { /* First probe for the Ethernet */ - /* Address PROM pattern */ - isa_probe(dev, iobase); - eisa_probe(dev, iobase); - - if ((tmp == num_ewrk3s) && (iobase != 0) && loading_module) { - printk("%s: ewrk3_probe() cannot find device at 0x%04lx.\n", dev->name, - iobase); - } - /* - ** Walk the device list to check that at least one device - ** initialised OK - */ - for (; (dev->priv == NULL) && (dev->next != NULL); dev = dev->next); + err = ewrk3_probe1(dev, dev->base_addr, dev->irq); + if (err) + goto out; + return dev; +out: + free_netdev(dev); + return ERR_PTR(err); + +} - if (dev->priv) - status = 0; - if (iobase == 0) - autoprobed = 1; - } +static int __init ewrk3_probe1(struct net_device *dev, u_long iobase, int irq) +{ + int err; - return status; + dev->base_addr = iobase; + dev->irq = irq; + + /* Address PROM pattern */ + err = isa_probe(dev, iobase); + if (err != 0) + err = eisa_probe(dev, iobase); + + if (err) + return err; + + err = register_netdev(dev); + if (err) + release_region(dev->base_addr, EWRK3_TOTAL_SIZE); + + return err; } static int __init @@ -396,8 +397,8 @@ u_char eeprom_image[EEPROM_MAX], chksum, eisa_cr = 0; /* - ** Stop the EWRK3. Enable the DBR ROM. Disable interrupts and remote boot. - ** This also disables the EISA_ENABLE bit in the EISA Control Register. + ** Stop the EWRK3. Enable the DBR ROM. Disable interrupts and remote boot. + ** This also disables the EISA_ENABLE bit in the EISA Control Register. */ if (iobase > 0x400) eisa_cr = inb(EISA_CR); @@ -409,232 +410,210 @@ icr &= 0x70; outb(icr, EWRK3_ICR); /* Disable all the IRQs */ - if (nicsr == (CSR_TXD | CSR_RXD)) { + if (nicsr == (CSR_TXD | CSR_RXD)) + return -ENXIO; - /* Check that the EEPROM is alive and well and not living on Pluto... */ - for (chksum = 0, i = 0; i < EEPROM_MAX; i += 2) { - union { - short val; - char c[2]; - } tmp; - - tmp.val = (short) Read_EEPROM(iobase, (i >> 1)); - eeprom_image[i] = tmp.c[0]; - eeprom_image[i + 1] = tmp.c[1]; - chksum += eeprom_image[i] + eeprom_image[i + 1]; - } - - if (chksum != 0) { /* Bad EEPROM Data! */ - printk("%s: Device has a bad on-board EEPROM.\n", dev->name); - status = -ENXIO; - } else { - EthwrkSignature(name, eeprom_image); - if (*name != '\0') { /* found a EWRK3 device */ - dev->base_addr = iobase; - - if (iobase > 0x400) { - outb(eisa_cr, EISA_CR); /* Rewrite the EISA CR */ - } - lemac = eeprom_image[EEPROM_CHIPVER]; - cmr = inb(EWRK3_CMR); - - if (((lemac == LeMAC) && ((cmr & CMR_NO_EEPROM) != CMR_NO_EEPROM)) || - ((lemac == LeMAC2) && !(cmr & CMR_HS))) { - printk("%s: %s at %#4lx", dev->name, name, iobase); - hard_strapped = 1; - } else if ((iobase & 0x0fff) == EWRK3_EISA_IO_PORTS) { - /* EISA slot address */ - printk("%s: %s at %#4lx (EISA slot %ld)", - dev->name, name, iobase, ((iobase >> 12) & 0x0f)); - } else { /* ISA port address */ - printk("%s: %s at %#4lx", dev->name, name, iobase); - } - - if (!status) { - printk(", h/w address "); - if (lemac != LeMAC2) - DevicePresent(iobase); /* need after EWRK3_INIT */ - status = get_hw_addr(dev, eeprom_image, lemac); - for (i = 0; i < ETH_ALEN - 1; i++) { /* get the ethernet addr. */ - printk("%2.2x:", dev->dev_addr[i]); - } - printk("%2.2x,\n", dev->dev_addr[i]); - if (status) { - printk(" which has an EEPROM CRC error.\n"); - status = -ENXIO; - } else { - if (lemac == LeMAC2) { /* Special LeMAC2 CMR things */ - cmr &= ~(CMR_RA | CMR_WB | CMR_LINK | CMR_POLARITY | CMR_0WS); - if (eeprom_image[EEPROM_MISC0] & READ_AHEAD) - cmr |= CMR_RA; - if (eeprom_image[EEPROM_MISC0] & WRITE_BEHIND) - cmr |= CMR_WB; - if (eeprom_image[EEPROM_NETMAN0] & NETMAN_POL) - cmr |= CMR_POLARITY; - if (eeprom_image[EEPROM_NETMAN0] & NETMAN_LINK) - cmr |= CMR_LINK; - if (eeprom_image[EEPROM_MISC0] & _0WS_ENA) - cmr |= CMR_0WS; - } - if (eeprom_image[EEPROM_SETUP] & SETUP_DRAM) - cmr |= CMR_DRAM; - outb(cmr, EWRK3_CMR); - - cr = inb(EWRK3_CR); /* Set up the Control Register */ - cr |= eeprom_image[EEPROM_SETUP] & SETUP_APD; - if (cr & SETUP_APD) - cr |= eeprom_image[EEPROM_SETUP] & SETUP_PS; - cr |= eeprom_image[EEPROM_MISC0] & FAST_BUS; - cr |= eeprom_image[EEPROM_MISC0] & ENA_16; - outb(cr, EWRK3_CR); + /* Check that the EEPROM is alive and well and not living on Pluto... */ + for (chksum = 0, i = 0; i < EEPROM_MAX; i += 2) { + union { + short val; + char c[2]; + } tmp; + + tmp.val = (short) Read_EEPROM(iobase, (i >> 1)); + eeprom_image[i] = tmp.c[0]; + eeprom_image[i + 1] = tmp.c[1]; + chksum += eeprom_image[i] + eeprom_image[i + 1]; + } + + if (chksum != 0) { /* Bad EEPROM Data! */ + printk("%s: Device has a bad on-board EEPROM.\n", dev->name); + return -ENXIO; + } + + EthwrkSignature(name, eeprom_image); + if (*name == '\0') + return -ENXIO; + + dev->base_addr = iobase; + + if (iobase > 0x400) { + outb(eisa_cr, EISA_CR); /* Rewrite the EISA CR */ + } + lemac = eeprom_image[EEPROM_CHIPVER]; + cmr = inb(EWRK3_CMR); + + if (((lemac == LeMAC) && ((cmr & CMR_NO_EEPROM) != CMR_NO_EEPROM)) || + ((lemac == LeMAC2) && !(cmr & CMR_HS))) { + printk("%s: %s at %#4lx", dev->name, name, iobase); + hard_strapped = 1; + } else if ((iobase & 0x0fff) == EWRK3_EISA_IO_PORTS) { + /* EISA slot address */ + printk("%s: %s at %#4lx (EISA slot %ld)", + dev->name, name, iobase, ((iobase >> 12) & 0x0f)); + } else { /* ISA port address */ + printk("%s: %s at %#4lx", dev->name, name, iobase); + } + + printk(", h/w address "); + if (lemac != LeMAC2) + DevicePresent(iobase); /* need after EWRK3_INIT */ + status = get_hw_addr(dev, eeprom_image, lemac); + for (i = 0; i < ETH_ALEN - 1; i++) { /* get the ethernet addr. */ + printk("%2.2x:", dev->dev_addr[i]); + } + printk("%2.2x,\n", dev->dev_addr[i]); + + if (status) { + printk(" which has an EEPROM CRC error.\n"); + return -ENXIO; + } + + if (lemac == LeMAC2) { /* Special LeMAC2 CMR things */ + cmr &= ~(CMR_RA | CMR_WB | CMR_LINK | CMR_POLARITY | CMR_0WS); + if (eeprom_image[EEPROM_MISC0] & READ_AHEAD) + cmr |= CMR_RA; + if (eeprom_image[EEPROM_MISC0] & WRITE_BEHIND) + cmr |= CMR_WB; + if (eeprom_image[EEPROM_NETMAN0] & NETMAN_POL) + cmr |= CMR_POLARITY; + if (eeprom_image[EEPROM_NETMAN0] & NETMAN_LINK) + cmr |= CMR_LINK; + if (eeprom_image[EEPROM_MISC0] & _0WS_ENA) + cmr |= CMR_0WS; + } + if (eeprom_image[EEPROM_SETUP] & SETUP_DRAM) + cmr |= CMR_DRAM; + outb(cmr, EWRK3_CMR); + + cr = inb(EWRK3_CR); /* Set up the Control Register */ + cr |= eeprom_image[EEPROM_SETUP] & SETUP_APD; + if (cr & SETUP_APD) + cr |= eeprom_image[EEPROM_SETUP] & SETUP_PS; + cr |= eeprom_image[EEPROM_MISC0] & FAST_BUS; + cr |= eeprom_image[EEPROM_MISC0] & ENA_16; + outb(cr, EWRK3_CR); - /* - ** Determine the base address and window length for the EWRK3 - ** RAM from the memory base register. - */ - mem_start = inb(EWRK3_MBR); - shmem_length = 0; - if (mem_start != 0) { - if ((mem_start >= 0x0a) && (mem_start <= 0x0f)) { - mem_start *= SHMEM_64K; - shmem_length = SHMEM_64K; - } else if ((mem_start >= 0x14) && (mem_start <= 0x1f)) { - mem_start *= SHMEM_32K; - shmem_length = SHMEM_32K; - } else if ((mem_start >= 0x40) && (mem_start <= 0xff)) { - mem_start = mem_start * SHMEM_2K + 0x80000; - shmem_length = SHMEM_2K; - } else { - status = -ENXIO; - } - } - /* - ** See the top of this source code for comments about - ** uncommenting this line. - */ + /* + ** Determine the base address and window length for the EWRK3 + ** RAM from the memory base register. + */ + mem_start = inb(EWRK3_MBR); + shmem_length = 0; + if (mem_start != 0) { + if ((mem_start >= 0x0a) && (mem_start <= 0x0f)) { + mem_start *= SHMEM_64K; + shmem_length = SHMEM_64K; + } else if ((mem_start >= 0x14) && (mem_start <= 0x1f)) { + mem_start *= SHMEM_32K; + shmem_length = SHMEM_32K; + } else if ((mem_start >= 0x40) && (mem_start <= 0xff)) { + mem_start = mem_start * SHMEM_2K + 0x80000; + shmem_length = SHMEM_2K; + } else { + return -ENXIO; + } + } + /* + ** See the top of this source code for comments about + ** uncommenting this line. + */ /* FORCE_2K_MODE; */ + + if (hard_strapped) { + printk(" is hard strapped.\n"); + } else if (mem_start) { + printk(" has a %dk RAM window", (int) (shmem_length >> 10)); + printk(" at 0x%.5lx", mem_start); + } else { + printk(" is in I/O only mode"); + } - if (!status) { - if (hard_strapped) { - printk(" is hard strapped.\n"); - } else if (mem_start) { - printk(" has a %dk RAM window", (int) (shmem_length >> 10)); - printk(" at 0x%.5lx", mem_start); - } else { - printk(" is in I/O only mode"); - } - - /* private area & initialise */ - dev->priv = (void *) kmalloc(sizeof(struct ewrk3_private), - GFP_KERNEL); - if (dev->priv == NULL) { - return -ENOMEM; - } - lp = (struct ewrk3_private *) dev->priv; - memset(dev->priv, 0, sizeof(struct ewrk3_private)); - lp->shmem_base = mem_start; - lp->shmem_length = shmem_length; - lp->lemac = lemac; - lp->hard_strapped = hard_strapped; - lp->led_mask = CR_LED; - spin_lock_init(&lp->hw_lock); - - lp->mPage = 64; - if (cmr & CMR_DRAM) - lp->mPage <<= 1; /* 2 DRAMS on module */ - - sprintf(lp->adapter_name, "%s (%s)", name, dev->name); - request_region(iobase, EWRK3_TOTAL_SIZE, lp->adapter_name); - - lp->irq_mask = ICR_TNEM | ICR_TXDM | ICR_RNEM | ICR_RXDM; - - if (!hard_strapped) { - /* - ** Enable EWRK3 board interrupts for autoprobing - */ - icr |= ICR_IE; /* Enable interrupts */ - outb(icr, EWRK3_ICR); - - /* The DMA channel may be passed in on this parameter. */ - dev->dma = 0; - - /* To auto-IRQ we enable the initialization-done and DMA err, - interrupts. For now we will always get a DMA error. */ - if (dev->irq < 2) { + lp = (struct ewrk3_private *) dev->priv; + lp->shmem_base = mem_start; + lp->shmem_length = shmem_length; + lp->lemac = lemac; + lp->hard_strapped = hard_strapped; + lp->led_mask = CR_LED; + spin_lock_init(&lp->hw_lock); + + lp->mPage = 64; + if (cmr & CMR_DRAM) + lp->mPage <<= 1; /* 2 DRAMS on module */ + + sprintf(lp->adapter_name, "%s (%s)", name, dev->name); + + lp->irq_mask = ICR_TNEM | ICR_TXDM | ICR_RNEM | ICR_RXDM; + + if (!hard_strapped) { + /* + ** Enable EWRK3 board interrupts for autoprobing + */ + icr |= ICR_IE; /* Enable interrupts */ + outb(icr, EWRK3_ICR); + + /* The DMA channel may be passed in on this parameter. */ + dev->dma = 0; + + /* To auto-IRQ we enable the initialization-done and DMA err, + interrupts. For now we will always get a DMA error. */ + if (dev->irq < 2) { #ifndef MODULE - u_char irqnum; - unsigned long irq_mask; + u_char irqnum; + unsigned long irq_mask; - irq_mask = probe_irq_on(); - - /* - ** Trigger a TNE interrupt. - */ - icr |= ICR_TNEM; - outb(1, EWRK3_TDQ); /* Write to the TX done queue */ - outb(icr, EWRK3_ICR); /* Unmask the TXD interrupt */ - - irqnum = irq[((icr & IRQ_SEL) >> 4)]; - - mdelay(20); - dev->irq = probe_irq_off(irq_mask); - if ((dev->irq) && (irqnum == dev->irq)) { - printk(" and uses IRQ%d.\n", dev->irq); - } else { - if (!dev->irq) { - printk(" and failed to detect IRQ line.\n"); - } else if ((irqnum == 1) && (lemac == LeMAC2)) { - printk(" and an illegal IRQ line detected.\n"); - } else { - printk(", but incorrect IRQ line detected.\n"); - } - status = -ENXIO; - } - - DISABLE_IRQs; /* Mask all interrupts */ - -#endif /* MODULE */ - } else { - printk(" and requires IRQ%d.\n", dev->irq); - } - } - if (status) - release_region(iobase, EWRK3_TOTAL_SIZE); - } else { - status = -ENXIO; - } - } - } + irq_mask = probe_irq_on(); + + /* + ** Trigger a TNE interrupt. + */ + icr |= ICR_TNEM; + outb(1, EWRK3_TDQ); /* Write to the TX done queue */ + outb(icr, EWRK3_ICR); /* Unmask the TXD interrupt */ + + irqnum = irq[((icr & IRQ_SEL) >> 4)]; + + mdelay(20); + dev->irq = probe_irq_off(irq_mask); + if ((dev->irq) && (irqnum == dev->irq)) { + printk(" and uses IRQ%d.\n", dev->irq); } else { - status = -ENXIO; - } - } - - if (!status) { - if (ewrk3_debug > 1) { - printk(version); + if (!dev->irq) { + printk(" and failed to detect IRQ line.\n"); + } else if ((irqnum == 1) && (lemac == LeMAC2)) { + printk(" and an illegal IRQ line detected.\n"); + } else { + printk(", but incorrect IRQ line detected.\n"); + } + return -ENXIO; } - /* The EWRK3-specific entries in the device structure. */ - dev->open = ewrk3_open; - dev->hard_start_xmit = ewrk3_queue_pkt; - dev->stop = ewrk3_close; - dev->get_stats = ewrk3_get_stats; - dev->set_multicast_list = set_multicast_list; - dev->do_ioctl = ewrk3_ioctl; - dev->tx_timeout = ewrk3_timeout; - dev->watchdog_timeo = QUEUE_PKT_TIMEOUT; - dev->mem_start = 0; + DISABLE_IRQs; /* Mask all interrupts */ - /* Fill in the generic field of the device structure. */ - ether_setup(dev); +#endif /* MODULE */ + } else { + printk(" and requires IRQ%d.\n", dev->irq); } - } else { - status = -ENXIO; } - return status; + + if (ewrk3_debug > 1) { + printk(version); + } + /* The EWRK3-specific entries in the device structure. */ + dev->open = ewrk3_open; + dev->hard_start_xmit = ewrk3_queue_pkt; + dev->stop = ewrk3_close; + dev->get_stats = ewrk3_get_stats; + dev->set_multicast_list = set_multicast_list; + dev->do_ioctl = ewrk3_ioctl; + dev->tx_timeout = ewrk3_timeout; + dev->watchdog_timeo = QUEUE_PKT_TIMEOUT; + + dev->mem_start = 0; + + return 0; } @@ -1269,15 +1248,15 @@ /* ** ISA bus I/O device probe */ -static void __init isa_probe(struct net_device *dev, u_long ioaddr) +static int __init isa_probe(struct net_device *dev, u_long ioaddr) { - int i = num_ewrk3s, maxSlots; + int i = num_ewrks3s, maxSlots; + int ret = -ENODEV; + u_long iobase; - if (!ioaddr && autoprobed) - return; /* Been here before ! */ if (ioaddr >= 0x400) - return; /* Not ISA */ + goto out; if (ioaddr == 0) { /* Autoprobing */ iobase = EWRK3_IO_BASE; /* Get the first slot address */ @@ -1287,38 +1266,37 @@ maxSlots = i + 1; } - for (; (i < maxSlots) && (dev != NULL); iobase += EWRK3_IOP_INC, i++) { - if (!check_region(iobase, EWRK3_TOTAL_SIZE)) { + for (; (i < maxSlots) && (dev != NULL); + iobase += EWRK3_IOP_INC, i++) + { + if (request_region(iobase, EWRK3_TOTAL_SIZE, dev->name)) { if (DevicePresent(iobase) == 0) { - if ((dev = alloc_device(dev, iobase)) != NULL) { - if (ewrk3_hw_init(dev, iobase) == 0) { - num_ewrk3s++; - } - num_eth++; - } + int irq = dev->irq; + ret = ewrk3_hw_init(dev, iobase); + if (!ret) + break; + dev->irq = irq; } - } else if (autoprobed) { - printk("%s: region already allocated at 0x%04lx.\n", dev->name, iobase); + release_region(iobase, EWRK3_TOTAL_SIZE); } } + out: - return; + return ret; } /* ** EISA bus I/O device probe. Probe from slot 1 since slot 0 is usually ** the motherboard. */ -static void __init eisa_probe(struct net_device *dev, u_long ioaddr) +static int __init eisa_probe(struct net_device *dev, u_long ioaddr) { int i, maxSlots; u_long iobase; - char name[EWRK3_STRLEN]; + int ret = -ENODEV; - if (!ioaddr && autoprobed) - return; /* Been here before ! */ if (ioaddr < 0x1000) - return; /* Not EISA */ + goto out; if (ioaddr == 0) { /* Autoprobing */ iobase = EISA_SLOT_INC; /* Get the first slot address */ @@ -1332,114 +1310,22 @@ for (i = 1; (i < maxSlots) && (dev != NULL); i++, iobase += EISA_SLOT_INC) { if (EISA_signature(name, EISA_ID) == 0) { - if (!check_region(iobase, EWRK3_TOTAL_SIZE)) { - if (DevicePresent(iobase) == 0) { - if ((dev = alloc_device(dev, iobase)) != NULL) { - if (ewrk3_hw_init(dev, iobase) == 0) { - num_ewrk3s++; - } - num_eth++; - } - } - } else if (autoprobed) { - printk("%s: region already allocated at 0x%04lx.\n", dev->name, iobase); + if (request_region(iobase, EWRK3_TOTAL_SIZE, dev->name) && + DevicePresent(iobase) == 0) { + int irq = dev->irq; + ret = ewrk3_hw_init(dev, iobase); + if (!ret) + break; + dev->irq = irq; } + release_region(iobase, EWRK3_TOTAL_SIZE); } } - return; + out: + return ret; } -/* - ** Search the entire 'eth' device list for a fixed probe. If a match isn't - ** found then check for an autoprobe or unused device location. If they - ** are not available then insert a new device structure at the end of - ** the current list. - */ -static struct net_device * __init alloc_device(struct net_device *dev, u_long iobase) -{ - struct net_device *adev = NULL; - int fixed = 0, new_dev = 0; - - num_eth = ewrk3_dev_index(dev->name); - if (loading_module) - return dev; - - while (1) { - if (((dev->base_addr == EWRK3_NDA) || (dev->base_addr == 0)) && !adev) { - adev = dev; - } else if ((dev->priv == NULL) && (dev->base_addr == iobase)) { - fixed = 1; - } else { - if (dev->next == NULL) { - new_dev = 1; - } else if (strncmp(dev->next->name, "eth", 3) != 0) { - new_dev = 1; - } - } - if ((dev->next == NULL) || new_dev || fixed) - break; - dev = dev->next; - num_eth++; - } - if (adev && !fixed) { - dev = adev; - num_eth = ewrk3_dev_index(dev->name); - new_dev = 0; - } - if (((dev->next == NULL) && - ((dev->base_addr != EWRK3_NDA) && (dev->base_addr != 0)) && !fixed) || - new_dev) { - num_eth++; /* New device */ - dev = insert_device(dev, iobase, ewrk3_probe); - } - return dev; -} - -/* - ** If at end of eth device list and can't use current entry, malloc - ** one up. If memory could not be allocated, print an error message. - */ -static struct net_device * __init -insert_device(struct net_device *dev, u_long iobase, int (*init) (struct net_device *)) -{ - struct net_device *new; - - new = (struct net_device *) kmalloc(sizeof(struct net_device) + 8, GFP_KERNEL); - if (new == NULL) { - printk("eth%d: Device not initialised, insufficient memory\n", num_eth); - return NULL; - } else { - new->next = dev->next; - dev->next = new; - dev = dev->next; /* point to the new device */ - if (num_eth > 9999) { - sprintf(dev->name, "eth????"); /* New device name */ - } else { - sprintf(dev->name, "eth%d", num_eth); /* New device name */ - } - dev->base_addr = iobase; /* assign the io address */ - dev->init = init; /* initialisation routine */ - } - - return dev; -} - -static int __init -ewrk3_dev_index(char *s) -{ - int i = 0, j = 0; - - for (; *s; s++) { - if (isdigit(*s)) { - j = 1; - i = (i * 10) + (*s - '0'); - } else if (j) - break; - } - - return i; -} /* ** Read the EWRK3 EEPROM using this routine @@ -2074,8 +1960,7 @@ #ifdef MODULE static struct net_device *ewrk3_devs[MAX_NUM_EWRK3S]; static int ndevs; -static int io[MAX_NUM_EWRK3S+1] = { 0x300, 0, }; /* <--- EDIT THESE LINES FOR YOUR CONFIGURATION */ -static int irq[MAX_NUM_EWRK3S+1] = { 5, 0, }; /* or use the insmod io= irq= options */ +static int io[MAX_NUM_EWRK3S+1] = { 0x300, 0, }; /* '21' below should really be 'MAX_NUM_EWRK3S' */ MODULE_PARM(io, "0-21i"); @@ -2083,50 +1968,39 @@ MODULE_PARM_DESC(io, "EtherWORKS 3 I/O base address(es)"); MODULE_PARM_DESC(irq, "EtherWORKS 3 IRQ number(s)"); -static void ewrk3_exit_module(void) +static __exit void ewrk3_exit_module(void) { int i; for( i=0; ipriv) { - kfree(ewrk3_devs[i]->priv); - ewrk3_devs[i]->priv = NULL; - } - ewrk3_devs[i]->irq = 0; - release_region(ewrk3_devs[i]->base_addr, EWRK3_TOTAL_SIZE); free_netdev(ewrk3_devs[i]); ewrk3_devs[i] = NULL; } } -static int ewrk3_init_module(void) +static __init int ewrk3_init_module(void) { int i=0; while( io[i] && irq[i] ) { - ewrk3_devs[ndevs] = kmalloc(sizeof(struct net_device), GFP_KERNEL); - if (!ewrk3_devs[ndevs]) - goto error; - memset(ewrk3_devs[ndevs], 0, sizeof(struct net_device)); - ewrk3_devs[ndevs]->base_addr = io[i]; - ewrk3_devs[ndevs]->irq = irq[i]; - ewrk3_devs[ndevs]->init = ewrk3_probe; - - if (register_netdev(ewrk3_devs[ndevs]) == 0) - ndevs++; - else - kfree(ewrk3_devs[ndevs]); + struct net_device *dev + = alloc_etherdev(sizeof(struct ewrk3_private)); + + if (!dev) + break; + if (ewrk3_probe1(dev, io[i], irq[i]) != 0) { + free_netdev(dev); + break; + } + + ewrk3_devs[ndevs++] = dev; i++; } return ndevs ? 0 : -EIO; - -error: - ewrk3_exit_module(); - return -ENOMEM; } diff -Nru a/drivers/net/fc/iph5526.c b/drivers/net/fc/iph5526.c --- a/drivers/net/fc/iph5526.c Thu Jan 22 18:59:24 2004 +++ b/drivers/net/fc/iph5526.c Thu Jan 22 18:59:24 2004 @@ -259,6 +259,7 @@ static int __init fcdev_init(struct net_device *dev) { + SET_MODULE_OWNER(dev); dev->open = iph5526_open; dev->stop = iph5526_close; dev->hard_start_xmit = iph5526_send_packet; @@ -2896,14 +2897,12 @@ static int iph5526_open(struct net_device *dev) { netif_start_queue(dev); - MOD_INC_USE_COUNT; return 0; } static int iph5526_close(struct net_device *dev) { netif_stop_queue(dev); - MOD_DEC_USE_COUNT; return 0; } @@ -4502,7 +4501,7 @@ iph5526_probe_pci(dev); err = register_netdev(dev); if (err < 0) { - kfree(dev); + free_netdev(dev); printk("iph5526.c: init_fcdev failed for card #%d\n", i+1); break; } diff -Nru a/drivers/net/fc/iph5526_scsi.h b/drivers/net/fc/iph5526_scsi.h --- a/drivers/net/fc/iph5526_scsi.h Thu Jan 22 18:59:25 2004 +++ b/drivers/net/fc/iph5526_scsi.h Thu Jan 22 18:59:25 2004 @@ -25,7 +25,7 @@ int iph5526_release(struct Scsi_Host *host); int iph5526_abort(Scsi_Cmnd *Cmnd); const char *iph5526_info(struct Scsi_Host *host); -int iph5526_biosparam(Disk * disk, struct block_device *n, int ip[]); +int iph5526_biosparam(struct Scsi_Disk * disk, struct block_device *n, int ip[]); #endif diff -Nru a/drivers/net/fec.c b/drivers/net/fec.c --- a/drivers/net/fec.c Thu Jan 22 18:59:23 2004 +++ b/drivers/net/fec.c Thu Jan 22 18:59:23 2004 @@ -1638,9 +1638,12 @@ /* Initialize the FEC Ethernet on 860T (or ColdFire 5272). */ + /* + * XXX: We need to clean up on failure exits here. + */ int __init fec_enet_init(struct net_device *dev) { - struct fec_enet_private *fep; + struct fec_enet_private *fep = dev->priv; unsigned long mem_addr; volatile cbd_t *bdp; cbd_t *cbd_base; @@ -1651,13 +1654,6 @@ if (found) return(-ENXIO); - /* Allocate some private information. - */ - fep = (struct fec_enet_private *)kmalloc(sizeof(*fep), GFP_KERNEL); - if (!fep) - return -ENOMEM; - memset(fep, 0, sizeof(*fep)); - /* Create an Ethernet device instance. */ fecp = fec_hwp; @@ -1694,6 +1690,7 @@ } mem_addr = __get_free_page(GFP_KERNEL); cbd_base = (cbd_t *)mem_addr; + /* XXX: missing check for allocation failure */ fec_uncache(mem_addr); @@ -1715,6 +1712,7 @@ /* Allocate a page. */ mem_addr = __get_free_page(GFP_KERNEL); + /* XXX: missing check for allocation failure */ fec_uncache(mem_addr); @@ -1761,9 +1759,6 @@ fec_request_intrs(dev, fecp); dev->base_addr = (unsigned long)fecp; - dev->priv = fep; - - ether_setup(dev); /* The FEC Ethernet specific entries in the device structure. */ dev->open = fec_enet_open; @@ -1949,14 +1944,28 @@ fecp->fec_mii_speed = fep->phy_speed; } -static struct net_device fec_dev = { - .init = fec_enet_init, -}; +static struct net_device *fec_dev; static int __init fec_enet_module_init(void) { - if (register_netdev(&fec_dev) != 0) + struct net_device *dev; + int err; + + dev = alloc_etherdev(sizeof(struct fec_enet_private)); + if (!dev) + return -ENOMEM; + err = fec_enet_init(dev); + if (err) { + free_netdev(dev); + return err; + } + + if (register_netdev(dev) != 0) { + /* XXX: missing cleanup here */ + free_netdev(dev); return -EIO; + } + fec_dev = dev; return(0); } diff -Nru a/drivers/net/fmv18x.c b/drivers/net/fmv18x.c --- a/drivers/net/fmv18x.c Thu Jan 22 18:59:23 2004 +++ b/drivers/net/fmv18x.c Thu Jan 22 18:59:23 2004 @@ -57,7 +57,7 @@ #include #include -static int fmv18x_probe_list[] __initdata = { +static unsigned fmv18x_probe_list[] __initdata = { 0x220, 0x240, 0x260, 0x280, 0x2a0, 0x2c0, 0x300, 0x340, 0 }; @@ -109,8 +109,6 @@ /* Index to functions, as function prototypes. */ -extern int fmv18x_probe(struct net_device *dev); - static int fmv18x_probe1(struct net_device *dev, short ioaddr); static int net_open(struct net_device *dev); static int net_send_packet(struct sk_buff *skb, struct net_device *dev); @@ -129,23 +127,50 @@ (detachable devices only). */ -int __init fmv18x_probe(struct net_device *dev) +static int io = 0x220; +static int irq; + +struct net_device * __init fmv18x_probe(int unit) { - int i; - int base_addr = dev->base_addr; + struct net_device *dev = alloc_etherdev(sizeof(struct net_local)); + unsigned *port; + int err = 0; + + if (!dev) + return ERR_PTR(-ENODEV); + + if (unit >= 0) { + sprintf(dev->name, "eth%d", unit); + netdev_boot_setup_check(dev); + io = dev->base_addr; + irq = dev->irq; + } SET_MODULE_OWNER(dev); - if (base_addr > 0x1ff) /* Check a single specified location. */ - return fmv18x_probe1(dev, base_addr); - else if (base_addr != 0) /* Don't probe at all. */ - return -ENXIO; - - for (i = 0; fmv18x_probe_list[i]; i++) - if (fmv18x_probe1(dev, fmv18x_probe_list[i]) == 0) - return 0; - - return -ENODEV; + if (io > 0x1ff) { /* Check a single specified location. */ + err = fmv18x_probe1(dev, io); + } else if (io != 0) { /* Don't probe at all. */ + err = -ENXIO; + } else { + for (port = fmv18x_probe_list; *port; port++) + if (fmv18x_probe1(dev, *port) == 0) + break; + if (!*port) + err = -ENODEV; + } + if (err) + goto out; + err = register_netdev(dev); + if (err) + goto out1; + return dev; +out1: + free_irq(dev->irq, dev); + release_region(dev->base_addr, FMV18X_IO_EXTENT); +out: + free_netdev(dev); + return ERR_PTR(err); } /* The Fujitsu datasheet suggests that the NIC be probed for by checking its @@ -160,7 +185,7 @@ { char irqmap[4] = {3, 7, 10, 15}; char irqmap_pnp[8] = {3, 4, 5, 7, 9, 10, 11, 15}; - unsigned int i, irq, retval; + unsigned int i, retval; struct net_local *lp; /* Resetting the chip doesn't reset the ISA interface, so don't bother. @@ -170,6 +195,9 @@ if (!request_region(ioaddr, FMV18X_IO_EXTENT, dev->name)) return -EBUSY; + dev->irq = irq; + dev->base_addr = ioaddr; + /* Check I/O address configuration and Fujitsu vendor code */ if (inb(ioaddr+FJ_MACADDR ) != 0x00 || inb(ioaddr+FJ_MACADDR+1) != 0x00 @@ -181,9 +209,8 @@ /* Check PnP mode for FMV-183/184/183A/184A. */ /* This PnP routine is very poor. IO and IRQ should be known. */ if (inb(ioaddr + FJ_STATUS1) & 0x20) { - irq = dev->irq; for (i = 0; i < 8; i++) { - if (irq == irqmap_pnp[i]) + if (dev->irq == irqmap_pnp[i]) break; } if (i == 8) { @@ -193,22 +220,19 @@ } else { if (fmv18x_probe_list[inb(ioaddr + FJ_CONFIG0) & 0x07] != ioaddr) return -ENODEV; - irq = irqmap[(inb(ioaddr + FJ_CONFIG0)>>6) & 0x03]; + dev->irq = irqmap[(inb(ioaddr + FJ_CONFIG0)>>6) & 0x03]; } /* Snarf the interrupt vector now. */ - retval = request_irq(irq, &net_interrupt, 0, dev->name, dev); + retval = request_irq(dev->irq, &net_interrupt, 0, dev->name, dev); if (retval) { printk ("FMV-18x found at %#3x, but it's unusable due to a conflict on" - "IRQ %d.\n", ioaddr, irq); + "IRQ %d.\n", ioaddr, dev->irq); goto out; } printk("%s: FMV-18x found at %#3x, IRQ %d, address ", dev->name, - ioaddr, irq); - - dev->base_addr = ioaddr; - dev->irq = irq; + ioaddr, dev->irq); for(i = 0; i < 6; i++) { unsigned char val = inb(ioaddr + FJ_MACADDR + i); @@ -279,14 +303,10 @@ dev->watchdog_timeo = HZ/10; dev->get_stats = net_get_stats; dev->set_multicast_list = set_multicast_list; - - /* Fill in the fields of 'dev' with ethernet-generic values. */ - - ether_setup(dev); return 0; out_irq: - free_irq(irq, dev); + free_irq(dev->irq, dev); out: release_region(ioaddr, FMV18X_IO_EXTENT); return retval; @@ -413,9 +433,7 @@ lp->tx_queue_len = 0; dev->trans_start = jiffies; lp->tx_started = 1; - } else if (lp->tx_queue_len < 4096 - 1502) - /* Yes, there is room for one more packet. */ - else + } else if (lp->tx_queue_len >= 4096 - 1502) /* No room for a packet */ netif_stop_queue(dev); dev_kfree_skb(skb); @@ -628,9 +646,7 @@ } #ifdef MODULE -static struct net_device dev_fmv18x; -static int io = 0x220; -static int irq; +static struct net_device *dev_fmv18x; MODULE_PARM(io, "i"); MODULE_PARM(irq, "i"); @@ -644,26 +660,19 @@ { if (io == 0) printk("fmv18x: You should not use auto-probing with insmod!\n"); - dev_fmv18x.base_addr = io; - dev_fmv18x.irq = irq; - dev_fmv18x.init = fmv18x_probe; - if (register_netdev(&dev_fmv18x) != 0) { - printk("fmv18x: register_netdev() returned non-zero.\n"); - return -EIO; - } + dev_fmv18x = fmv18x_probe(-1); + if (IS_ERR(dev_fmv18x)) + return PTR_ERR(dev_fmv18x); return 0; } void cleanup_module(void) { - unregister_netdev(&dev_fmv18x); - kfree(dev_fmv18x.priv); - dev_fmv18x.priv = NULL; - - /* If we don't do this, we can't re-insmod it later. */ - free_irq(dev_fmv18x.irq, &dev_fmv18x); - release_region(dev_fmv18x.base_addr, FMV18X_IO_EXTENT); + unregister_netdev(dev_fmv18x); + free_irq(dev_fmv18x->irq, dev_fmv18x); + release_region(dev_fmv18x->base_addr, FMV18X_IO_EXTENT); + free_netdev(dev_fmv18x); } #endif /* MODULE */ diff -Nru a/drivers/net/gt96100eth.c b/drivers/net/gt96100eth.c --- a/drivers/net/gt96100eth.c Thu Jan 22 18:59:26 2004 +++ b/drivers/net/gt96100eth.c Thu Jan 22 18:59:26 2004 @@ -729,10 +729,12 @@ return -EBUSY; } - dev = init_etherdev(0, sizeof(struct gt96100_private)); + dev = alloc_etherdev(sizeof(struct gt96100_private)); + if (!dev) + goto out; gtif->dev = dev; - /* private struct aligned and zeroed by init_etherdev */ + /* private struct aligned and zeroed by alloc_etherdev */ /* Fill in the 'dev' fields. */ dev->base_addr = gtif->iobase; dev->irq = gtif->irq; @@ -740,7 +742,7 @@ if ((retval = parse_mac_addr(dev, gtif->mac_str))) { err("%s: MAC address parse failed\n", __FUNCTION__); retval = -EINVAL; - goto free_region; + goto out1; } gp = dev->priv; @@ -768,7 +770,7 @@ &gp->rx_ring_dma); if (gp->rx_ring == NULL) { retval = -ENOMEM; - goto free_region; + goto out1; } gp->tx_ring = (gt96100_td_t *)(gp->rx_ring + RX_RING_SIZE); @@ -781,11 +783,8 @@ gp->rx_buff = dmaalloc(PKT_BUF_SZ*RX_RING_SIZE, &gp->rx_buff_dma); if (gp->rx_buff == NULL) { - dmafree(sizeof(gt96100_rd_t) * RX_RING_SIZE - + sizeof(gt96100_td_t) * TX_RING_SIZE, - gp->rx_ring); retval = -ENOMEM; - goto free_region; + goto out2; } } @@ -797,12 +796,8 @@ gp->hash_table = (char*)dmaalloc(RX_HASH_TABLE_SIZE, &gp->hash_table_dma); if (gp->hash_table == NULL) { - dmafree(sizeof(gt96100_rd_t) * RX_RING_SIZE - + sizeof(gt96100_td_t) * TX_RING_SIZE, - gp->rx_ring); - dmafree(PKT_BUF_SZ*RX_RING_SIZE, gp->rx_buff); retval = -ENOMEM; - goto free_region; + goto out3; } } @@ -819,14 +814,23 @@ dev->tx_timeout = gt96100_tx_timeout; dev->watchdog_timeo = GT96100ETH_TX_TIMEOUT; - /* Fill in the fields of the device structure with ethernet values. */ - ether_setup(dev); + retval = register_netdev(dev); + if (retval) + goto out4; return 0; - free_region: - release_region(gtif->iobase, GT96100_ETH_IO_SIZE); - unregister_netdev(dev); +out4: + dmafree(RX_HASH_TABLE_SIZE, gp->hash_table_dma); +out3: + dmafree(PKT_BUF_SZ*RX_RING_SIZE, gp->rx_buff); +out2: + dmafree(sizeof(gt96100_rd_t) * RX_RING_SIZE + + sizeof(gt96100_td_t) * TX_RING_SIZE, + gp->rx_ring); +out1: free_netdev (dev); +out: + release_region(gtif->iobase, GT96100_ETH_IO_SIZE); err("%s failed. Returns %d\n", __FUNCTION__, retval); return retval; } @@ -1573,9 +1577,14 @@ if (gtif->dev != NULL) { struct gt96100_private *gp = (struct gt96100_private *)gtif->dev->priv; - release_region(gtif->iobase, gp->io_size); unregister_netdev(gtif->dev); - free_netdev (gtif->dev); + dmafree(RX_HASH_TABLE_SIZE, gp->hash_table_dma); + dmafree(PKT_BUF_SZ*RX_RING_SIZE, gp->rx_buff); + dmafree(sizeof(gt96100_rd_t) * RX_RING_SIZE + + sizeof(gt96100_td_t) * TX_RING_SIZE, + gp->rx_ring); + free_netdev(gtif->dev); + release_region(gtif->iobase, gp->io_size); } } } diff -Nru a/drivers/net/hamradio/baycom_epp.c b/drivers/net/hamradio/baycom_epp.c --- a/drivers/net/hamradio/baycom_epp.c Thu Jan 22 18:59:27 2004 +++ b/drivers/net/hamradio/baycom_epp.c Thu Jan 22 18:59:27 2004 @@ -1275,7 +1275,7 @@ * If dev->base_addr == 2, allocate space for the device and return success * (detachable devices only). */ -static int baycom_probe(struct net_device *dev) +static void baycom_probe(struct net_device *dev) { static char ax25_bcast[AX25_ADDR_LEN] = { 'Q' << 1, 'S' << 1, 'T' << 1, ' ' << 1, ' ' << 1, ' ' << 1, '0' << 1 @@ -1288,9 +1288,6 @@ }; struct baycom_state *bc; - if (!dev) - return -ENXIO; - baycom_paranoia_check(dev, "baycom_probe", -ENXIO); /* * not a real probe! only initialize data structures */ @@ -1332,8 +1329,6 @@ /* New style flags */ dev->flags = 0; - - return 0; } /* --------------------------------------------------------------------- */ @@ -1368,7 +1363,7 @@ /* * initialize part of the device struct */ - dev->init = baycom_probe; + baycom_probe(dev); } static int __init init_baycomepp(void) @@ -1401,7 +1396,7 @@ if (register_netdev(dev)) { printk(KERN_WARNING "%s: cannot register net device %s\n", bc_drvname, dev->name); - kfree(dev); + free_netdev(dev); break; } if (set_hw && baycom_setmode(dev->priv, mode[i])) diff -Nru a/drivers/net/hamradio/bpqether.c b/drivers/net/hamradio/bpqether.c --- a/drivers/net/hamradio/bpqether.c Thu Jan 22 18:59:25 2004 +++ b/drivers/net/hamradio/bpqether.c Thu Jan 22 18:59:25 2004 @@ -547,7 +547,7 @@ error: dev_put(edev); - kfree(ndev); + free_netdev(ndev); return err; } diff -Nru a/drivers/net/hamradio/dmascc.c b/drivers/net/hamradio/dmascc.c --- a/drivers/net/hamradio/dmascc.c Thu Jan 22 18:59:25 2004 +++ b/drivers/net/hamradio/dmascc.c Thu Jan 22 18:59:25 2004 @@ -242,7 +242,7 @@ struct scc_info { int irq_used; int twin_serial_cfg; - struct net_device dev[2]; + struct net_device *dev[2]; struct scc_priv priv[2]; struct scc_info *next; spinlock_t register_lock; /* Per device register lock */ @@ -310,18 +310,19 @@ info = first; /* Unregister devices */ - for (i = 0; i < 2; i++) { - if (info->dev[i].name) - unregister_netdev(&info->dev[i]); - } + for (i = 0; i < 2; i++) + unregister_netdev(info->dev[i]); /* Reset board */ if (info->priv[0].type == TYPE_TWIN) - outb(0, info->dev[0].base_addr + TWIN_SERIAL_CFG); + outb(0, info->dev[0]->base_addr + TWIN_SERIAL_CFG); write_scc(&info->priv[0], R9, FHWRES); - release_region(info->dev[0].base_addr, + release_region(info->dev[0]->base_addr, hw[info->priv[0].type].io_size); + for (i = 0; i < 2; i++) + free_netdev(info->dev[i]); + /* Free memory */ first = info->next; kfree(info); @@ -443,156 +444,193 @@ module_init(dmascc_init); module_exit(dmascc_exit); +static void dev_setup(struct net_device *dev) +{ + dev->type = ARPHRD_AX25; + dev->hard_header_len = 73; + dev->mtu = 1500; + dev->addr_len = 7; + dev->tx_queue_len = 64; + memcpy(dev->broadcast, ax25_broadcast, 7); + memcpy(dev->dev_addr, ax25_test, 7); +} -int __init setup_adapter(int card_base, int type, int n) { - int i, irq, chip; - struct scc_info *info; - struct net_device *dev; - struct scc_priv *priv; - unsigned long time; - unsigned int irqs; - int tmr_base = card_base + hw[type].tmr_offset; - int scc_base = card_base + hw[type].scc_offset; - char *chipnames[] = CHIPNAMES; - - /* Allocate memory */ - info = kmalloc(sizeof(struct scc_info), GFP_KERNEL | GFP_DMA); - if (!info) { - printk(KERN_ERR "dmascc: could not allocate memory for %s at %#3x\n", - hw[type].name, card_base); - return -1; - } +static int __init setup_adapter(int card_base, int type, int n) +{ + int i, irq, chip; + struct scc_info *info; + struct net_device *dev; + struct scc_priv *priv; + unsigned long time; + unsigned int irqs; + int tmr_base = card_base + hw[type].tmr_offset; + int scc_base = card_base + hw[type].scc_offset; + char *chipnames[] = CHIPNAMES; + + /* Allocate memory */ + info = kmalloc(sizeof(struct scc_info), GFP_KERNEL | GFP_DMA); + if (!info) { + printk(KERN_ERR "dmascc: " + "could not allocate memory for %s at %#3x\n", + hw[type].name, card_base); + goto out; + } - /* Initialize what is necessary for write_scc and write_scc_data */ - memset(info, 0, sizeof(struct scc_info)); - spin_lock_init(&info->register_lock); - - priv = &info->priv[0]; - priv->type = type; - priv->card_base = card_base; - priv->scc_cmd = scc_base + SCCA_CMD; - priv->scc_data = scc_base + SCCA_DATA; - priv->register_lock = &info->register_lock; - - /* Reset SCC */ - write_scc(priv, R9, FHWRES | MIE | NV); - - /* Determine type of chip by enabling SDLC/HDLC enhancements */ - write_scc(priv, R15, SHDLCE); - if (!read_scc(priv, R15)) { - /* WR7' not present. This is an ordinary Z8530 SCC. */ - chip = Z8530; - } else { - /* Put one character in TX FIFO */ - write_scc_data(priv, 0, 0); - if (read_scc(priv, R0) & Tx_BUF_EMP) { - /* TX FIFO not full. This is a Z85230 ESCC with a 4-byte FIFO. */ - chip = Z85230; - } else { - /* TX FIFO full. This is a Z85C30 SCC with a 1-byte FIFO. */ - chip = Z85C30; - } - } - write_scc(priv, R15, 0); + /* Initialize what is necessary for write_scc and write_scc_data */ + memset(info, 0, sizeof(struct scc_info)); - /* Start IRQ auto-detection */ - irqs = probe_irq_on(); + info->dev[0] = alloc_netdev(0, "", dev_setup); + if (!info->dev[0]) { + printk(KERN_ERR "dmascc: " + "could not allocate memory for %s at %#3x\n", + hw[type].name, card_base); + goto out1; + } - /* Enable interrupts */ - if (type == TYPE_TWIN) { - outb(0, card_base + TWIN_DMA_CFG); - inb(card_base + TWIN_CLR_TMR1); - inb(card_base + TWIN_CLR_TMR2); - outb((info->twin_serial_cfg = TWIN_EI), card_base + TWIN_SERIAL_CFG); - } else { - write_scc(priv, R15, CTSIE); - write_scc(priv, R0, RES_EXT_INT); - write_scc(priv, R1, EXT_INT_ENAB); - } + info->dev[1] = alloc_netdev(0, "", dev_setup); + if (!info->dev[1]) { + printk(KERN_ERR "dmascc: " + "could not allocate memory for %s at %#3x\n", + hw[type].name, card_base); + goto out2; + } + spin_lock_init(&info->register_lock); - /* Start timer */ - outb(1, tmr_base + TMR_CNT1); - outb(0, tmr_base + TMR_CNT1); - - /* Wait and detect IRQ */ - time = jiffies; while (jiffies - time < 2 + HZ / TMR_0_HZ); - irq = probe_irq_off(irqs); - - /* Clear pending interrupt, disable interrupts */ - if (type == TYPE_TWIN) { - inb(card_base + TWIN_CLR_TMR1); - } else { - write_scc(priv, R1, 0); - write_scc(priv, R15, 0); - write_scc(priv, R0, RES_EXT_INT); - } + priv = &info->priv[0]; + priv->type = type; + priv->card_base = card_base; + priv->scc_cmd = scc_base + SCCA_CMD; + priv->scc_data = scc_base + SCCA_DATA; + priv->register_lock = &info->register_lock; + + /* Reset SCC */ + write_scc(priv, R9, FHWRES | MIE | NV); + + /* Determine type of chip by enabling SDLC/HDLC enhancements */ + write_scc(priv, R15, SHDLCE); + if (!read_scc(priv, R15)) { + /* WR7' not present. This is an ordinary Z8530 SCC. */ + chip = Z8530; + } else { + /* Put one character in TX FIFO */ + write_scc_data(priv, 0, 0); + if (read_scc(priv, R0) & Tx_BUF_EMP) { + /* TX FIFO not full. This is a Z85230 ESCC with a 4-byte FIFO. */ + chip = Z85230; + } else { + /* TX FIFO full. This is a Z85C30 SCC with a 1-byte FIFO. */ + chip = Z85C30; + } + } + write_scc(priv, R15, 0); - if (irq <= 0) { - printk(KERN_ERR "dmascc: could not find irq of %s at %#3x (irq=%d)\n", - hw[type].name, card_base, irq); - kfree(info); - return -1; - } + /* Start IRQ auto-detection */ + irqs = probe_irq_on(); - /* Set up data structures */ - for (i = 0; i < 2; i++) { - dev = &info->dev[i]; - priv = &info->priv[i]; - priv->type = type; - priv->chip = chip; - priv->dev = dev; - priv->info = info; - priv->channel = i; - spin_lock_init(&priv->ring_lock); - priv->register_lock = &info->register_lock; - priv->card_base = card_base; - priv->scc_cmd = scc_base + (i ? SCCB_CMD : SCCA_CMD); - priv->scc_data = scc_base + (i ? SCCB_DATA : SCCA_DATA); - priv->tmr_cnt = tmr_base + (i ? TMR_CNT2 : TMR_CNT1); - priv->tmr_ctrl = tmr_base + TMR_CTRL; - priv->tmr_mode = i ? 0xb0 : 0x70; - priv->param.pclk_hz = hw[type].pclk_hz; - priv->param.brg_tc = -1; - priv->param.clocks = TCTRxCP | RCRTxCP; - priv->param.persist = 256; - priv->param.dma = -1; - INIT_WORK(&priv->rx_work, rx_bh, priv); - dev->priv = priv; -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0) - if (sizeof(dev->name) == sizeof(char *)) dev->name = priv->name; -#endif - sprintf(dev->name, "dmascc%i", 2*n+i); - SET_MODULE_OWNER(dev); - dev->base_addr = card_base; - dev->irq = irq; - dev->open = scc_open; - dev->stop = scc_close; - dev->do_ioctl = scc_ioctl; - dev->hard_start_xmit = scc_send_packet; - dev->get_stats = scc_get_stats; - dev->hard_header = ax25_encapsulate; - dev->rebuild_header = ax25_rebuild_header; - dev->set_mac_address = scc_set_mac_address; - dev->type = ARPHRD_AX25; - dev->hard_header_len = 73; - dev->mtu = 1500; - dev->addr_len = 7; - dev->tx_queue_len = 64; - memcpy(dev->broadcast, ax25_broadcast, 7); - memcpy(dev->dev_addr, ax25_test, 7); - rtnl_lock(); - if (register_netdevice(dev)) { - printk(KERN_ERR "dmascc: could not register %s\n", dev->name); - } - rtnl_unlock(); - } + /* Enable interrupts */ + if (type == TYPE_TWIN) { + outb(0, card_base + TWIN_DMA_CFG); + inb(card_base + TWIN_CLR_TMR1); + inb(card_base + TWIN_CLR_TMR2); + info->twin_serial_cfg = TWIN_EI; + outb(info->twin_serial_cfg, card_base + TWIN_SERIAL_CFG); + } else { + write_scc(priv, R15, CTSIE); + write_scc(priv, R0, RES_EXT_INT); + write_scc(priv, R1, EXT_INT_ENAB); + } + + /* Start timer */ + outb(1, tmr_base + TMR_CNT1); + outb(0, tmr_base + TMR_CNT1); + + /* Wait and detect IRQ */ + time = jiffies; while (jiffies - time < 2 + HZ / TMR_0_HZ); + irq = probe_irq_off(irqs); + + /* Clear pending interrupt, disable interrupts */ + if (type == TYPE_TWIN) { + inb(card_base + TWIN_CLR_TMR1); + } else { + write_scc(priv, R1, 0); + write_scc(priv, R15, 0); + write_scc(priv, R0, RES_EXT_INT); + } + + if (irq <= 0) { + printk(KERN_ERR "dmascc: could not find irq of %s at %#3x (irq=%d)\n", + hw[type].name, card_base, irq); + goto out3; + } + + /* Set up data structures */ + for (i = 0; i < 2; i++) { + dev = info->dev[i]; + priv = &info->priv[i]; + priv->type = type; + priv->chip = chip; + priv->dev = dev; + priv->info = info; + priv->channel = i; + spin_lock_init(&priv->ring_lock); + priv->register_lock = &info->register_lock; + priv->card_base = card_base; + priv->scc_cmd = scc_base + (i ? SCCB_CMD : SCCA_CMD); + priv->scc_data = scc_base + (i ? SCCB_DATA : SCCA_DATA); + priv->tmr_cnt = tmr_base + (i ? TMR_CNT2 : TMR_CNT1); + priv->tmr_ctrl = tmr_base + TMR_CTRL; + priv->tmr_mode = i ? 0xb0 : 0x70; + priv->param.pclk_hz = hw[type].pclk_hz; + priv->param.brg_tc = -1; + priv->param.clocks = TCTRxCP | RCRTxCP; + priv->param.persist = 256; + priv->param.dma = -1; + INIT_WORK(&priv->rx_work, rx_bh, priv); + dev->priv = priv; + sprintf(dev->name, "dmascc%i", 2*n+i); + SET_MODULE_OWNER(dev); + dev->base_addr = card_base; + dev->irq = irq; + dev->open = scc_open; + dev->stop = scc_close; + dev->do_ioctl = scc_ioctl; + dev->hard_start_xmit = scc_send_packet; + dev->get_stats = scc_get_stats; + dev->hard_header = ax25_encapsulate; + dev->rebuild_header = ax25_rebuild_header; + dev->set_mac_address = scc_set_mac_address; + } + if (register_netdev(info->dev[0])) { + printk(KERN_ERR "dmascc: could not register %s\n", + info->dev[0]->name); + goto out3; + } + if (register_netdev(info->dev[1])) { + printk(KERN_ERR "dmascc: could not register %s\n", + info->dev[1]->name); + goto out4; + } - info->next = first; - first = info; - printk(KERN_INFO "dmascc: found %s (%s) at %#3x, irq %d\n", hw[type].name, - chipnames[chip], card_base, irq); - return 0; + info->next = first; + first = info; + printk(KERN_INFO "dmascc: found %s (%s) at %#3x, irq %d\n", hw[type].name, + chipnames[chip], card_base, irq); + return 0; + +out4: + unregister_netdev(info->dev[0]); +out3: + if (info->priv[0].type == TYPE_TWIN) + outb(0, info->dev[0]->base_addr + TWIN_SERIAL_CFG); + write_scc(&info->priv[0], R9, FHWRES); + free_netdev(info->dev[1]); +out2: + free_netdev(info->dev[0]); +out1: + kfree(info); +out: + return -1; } diff -Nru a/drivers/net/hamradio/hdlcdrv.c b/drivers/net/hamradio/hdlcdrv.c --- a/drivers/net/hamradio/hdlcdrv.c Thu Jan 22 18:59:26 2004 +++ b/drivers/net/hamradio/hdlcdrv.c Thu Jan 22 18:59:26 2004 @@ -832,7 +832,7 @@ if (err < 0) { printk(KERN_WARNING "hdlcdrv: cannot register net " "device %s\n", dev->name); - kfree(dev); + free_netdev(dev); dev = ERR_PTR(err); } return dev; diff -Nru a/drivers/net/hamradio/yam.c b/drivers/net/hamradio/yam.c --- a/drivers/net/hamradio/yam.c Thu Jan 22 18:59:26 2004 +++ b/drivers/net/hamradio/yam.c Thu Jan 22 18:59:26 2004 @@ -1192,7 +1192,7 @@ struct net_device *dev = yam_devs[i]; if (dev) { unregister_netdev(dev); - kfree(dev); + free_netdev(dev); } } diff -Nru a/drivers/net/hp-plus.c b/drivers/net/hp-plus.c --- a/drivers/net/hp-plus.c Thu Jan 22 18:59:23 2004 +++ b/drivers/net/hp-plus.c Thu Jan 22 18:59:23 2004 @@ -92,7 +92,6 @@ EnableIRQ = 4, FakeIntr = 8, BootROMEnb = 0x10, IOEnb = 0x20, MemEnable = 0x40, ZeroWait = 0x80, MemDisable = 0x1000, }; -int hp_plus_probe(struct net_device *dev); static int hpp_probe1(struct net_device *dev, int ioaddr); static void hpp_reset_8390(struct net_device *dev); @@ -115,10 +114,11 @@ /* Probe a list of addresses for an HP LAN+ adaptor. This routine is almost boilerplate. */ -int __init hp_plus_probe(struct net_device *dev) +static int __init do_hpp_probe(struct net_device *dev) { int i; int base_addr = dev->base_addr; + int irq = dev->irq; SET_MODULE_OWNER(dev); @@ -127,13 +127,46 @@ else if (base_addr != 0) /* Don't probe at all. */ return -ENXIO; - for (i = 0; hpplus_portlist[i]; i++) + for (i = 0; hpplus_portlist[i]; i++) { if (hpp_probe1(dev, hpplus_portlist[i]) == 0) return 0; + dev->irq = irq; + } return -ENODEV; } +static void cleanup_card(struct net_device *dev) +{ + /* NB: hpp_close() handles free_irq */ + release_region(dev->base_addr - NIC_OFFSET, HP_IO_EXTENT); +} + +struct net_device * __init hp_plus_probe(int unit) +{ + struct net_device *dev = alloc_ei_netdev(); + int err; + + if (!dev) + return ERR_PTR(-ENOMEM); + + sprintf(dev->name, "eth%d", unit); + netdev_boot_setup_check(dev); + + err = do_hpp_probe(dev); + if (err) + goto out; + err = register_netdev(dev); + if (err) + goto out1; + return dev; +out1: + cleanup_card(dev); +out: + free_netdev(dev); + return ERR_PTR(err); +} + /* Do the interesting part of the probe at a single address. */ static int __init hpp_probe1(struct net_device *dev, int ioaddr) { @@ -179,13 +212,6 @@ printk(" ID %4.4x", inw(ioaddr + 12)); } - /* Allocate dev->priv and fill in 8390 specific dev fields. */ - if (ethdev_init(dev)) { - printk ("hp-plus.c: unable to allocate memory for dev->priv.\n"); - retval = -ENOMEM; - goto out; - } - /* Read the IRQ line. */ outw(HW_Page, ioaddr + HP_PAGING); { @@ -210,6 +236,9 @@ dev->open = &hpp_open; dev->stop = &hpp_close; +#ifdef CONFIG_NET_POLL_CONTROLLER + dev->poll_controller = ei_poll; +#endif ei_status.name = name; ei_status.word16 = 0; /* Agggghhhhh! Debug time: 2 days! */ @@ -400,7 +429,7 @@ #ifdef MODULE #define MAX_HPP_CARDS 4 /* Max number of HPP cards per module */ -static struct net_device dev_hpp[MAX_HPP_CARDS]; +static struct net_device *dev_hpp[MAX_HPP_CARDS]; static int io[MAX_HPP_CARDS]; static int irq[MAX_HPP_CARDS]; @@ -416,27 +445,33 @@ int init_module(void) { + struct net_device *dev; int this_dev, found = 0; for (this_dev = 0; this_dev < MAX_HPP_CARDS; this_dev++) { - struct net_device *dev = &dev_hpp[this_dev]; - dev->irq = irq[this_dev]; - dev->base_addr = io[this_dev]; - dev->init = hp_plus_probe; if (io[this_dev] == 0) { if (this_dev != 0) break; /* only autoprobe 1st one */ printk(KERN_NOTICE "hp-plus.c: Presently autoprobing (not recommended) for a single card.\n"); } - if (register_netdev(dev) != 0) { - printk(KERN_WARNING "hp-plus.c: No HP-Plus card found (i/o = 0x%x).\n", io[this_dev]); - if (found != 0) { /* Got at least one. */ - return 0; + dev = alloc_ei_netdev(); + if (!dev) + break; + dev->irq = irq[this_dev]; + dev->base_addr = io[this_dev]; + if (do_hpp_probe(dev) == 0) { + if (register_netdev(dev) == 0) { + dev_hpp[found++] = dev; + continue; } - return -ENXIO; + cleanup_card(dev); } - found++; + free_netdev(dev); + printk(KERN_WARNING "hp-plus.c: No HP-Plus card found (i/o = 0x%x).\n", io[this_dev]); + break; } - return 0; + if (found) + return 0; + return -ENXIO; } void @@ -445,14 +480,11 @@ int this_dev; for (this_dev = 0; this_dev < MAX_HPP_CARDS; this_dev++) { - struct net_device *dev = &dev_hpp[this_dev]; - if (dev->priv != NULL) { - int ioaddr = dev->base_addr - NIC_OFFSET; - void *priv = dev->priv; - /* NB: hpp_close() handles free_irq */ - release_region(ioaddr, HP_IO_EXTENT); + struct net_device *dev = dev_hpp[this_dev]; + if (dev) { unregister_netdev(dev); - kfree(priv); + cleanup_card(dev); + free_netdev(dev); } } } diff -Nru a/drivers/net/hp.c b/drivers/net/hp.c --- a/drivers/net/hp.c Thu Jan 22 18:59:24 2004 +++ b/drivers/net/hp.c Thu Jan 22 18:59:24 2004 @@ -55,7 +55,6 @@ #define HP_8BSTOP_PG 0x80 /* Last page +1 of RX ring */ #define HP_16BSTOP_PG 0xFF /* Same, for 16 bit cards. */ -int hp_probe(struct net_device *dev); static int hp_probe1(struct net_device *dev, int ioaddr); static int hp_open(struct net_device *dev); @@ -79,10 +78,11 @@ Also initialize the card and fill in STATION_ADDR with the station address. */ -int __init hp_probe(struct net_device *dev) +static int __init do_hp_probe(struct net_device *dev) { int i; int base_addr = dev->base_addr; + int irq = dev->irq; SET_MODULE_OWNER(dev); @@ -91,13 +91,46 @@ else if (base_addr != 0) /* Don't probe at all. */ return -ENXIO; - for (i = 0; hppclan_portlist[i]; i++) + for (i = 0; hppclan_portlist[i]; i++) { if (hp_probe1(dev, hppclan_portlist[i]) == 0) return 0; + dev->irq = irq; + } return -ENODEV; } +static void cleanup_card(struct net_device *dev) +{ + free_irq(dev->irq, dev); + release_region(dev->base_addr - NIC_OFFSET, HP_IO_EXTENT); +} + +struct net_device * __init hp_probe(int unit) +{ + struct net_device *dev = alloc_ei_netdev(); + int err; + + if (!dev) + return ERR_PTR(-ENOMEM); + + sprintf(dev->name, "eth%d", unit); + netdev_boot_setup_check(dev); + + err = do_hp_probe(dev); + if (err) + goto out; + err = register_netdev(dev); + if (err) + goto out1; + return dev; +out1: + cleanup_card(dev); +out: + free_netdev(dev); + return ERR_PTR(err); +} + static int __init hp_probe1(struct net_device *dev, int ioaddr) { int i, retval, board_id, wordmode; @@ -131,13 +164,6 @@ if (ei_debug && version_printed++ == 0) printk(version); - /* Allocate dev->priv and fill in 8390 specific dev fields. */ - if (ethdev_init(dev)) { - printk (" unable to get memory for dev->priv.\n"); - retval = -ENOMEM; - goto out; - } - printk("%s: %s (ID %02x) at %#3x,", dev->name, name, board_id, ioaddr); for(i = 0; i < ETHER_ADDR_LEN; i++) @@ -166,14 +192,14 @@ if (*irqp == 0) { printk(" no free IRQ lines.\n"); retval = -EBUSY; - goto out1; + goto out; } } else { if (dev->irq == 2) dev->irq = 9; if ((retval = request_irq(dev->irq, ei_interrupt, 0, dev->name, dev))) { printk (" unable to get IRQ %d.\n", dev->irq); - goto out1; + goto out; } } @@ -181,6 +207,9 @@ dev->base_addr = ioaddr + NIC_OFFSET; dev->open = &hp_open; dev->stop = &hp_close; +#ifdef CONFIG_NET_POLL_CONTROLLER + dev->poll_controller = ei_poll; +#endif ei_status.name = name; ei_status.word16 = wordmode; @@ -195,9 +224,6 @@ hp_init_card(dev); return 0; -out1: - kfree(dev->priv); - dev->priv = NULL; out: release_region(ioaddr, HP_IO_EXTENT); return retval; @@ -372,7 +398,7 @@ #ifdef MODULE #define MAX_HP_CARDS 4 /* Max number of HP cards per module */ -static struct net_device dev_hp[MAX_HP_CARDS]; +static struct net_device *dev_hp[MAX_HP_CARDS]; static int io[MAX_HP_CARDS]; static int irq[MAX_HP_CARDS]; @@ -388,27 +414,33 @@ int init_module(void) { + struct net_device *dev; int this_dev, found = 0; for (this_dev = 0; this_dev < MAX_HP_CARDS; this_dev++) { - struct net_device *dev = &dev_hp[this_dev]; - dev->irq = irq[this_dev]; - dev->base_addr = io[this_dev]; - dev->init = hp_probe; if (io[this_dev] == 0) { if (this_dev != 0) break; /* only autoprobe 1st one */ printk(KERN_NOTICE "hp.c: Presently autoprobing (not recommended) for a single card.\n"); } - if (register_netdev(dev) != 0) { - printk(KERN_WARNING "hp.c: No HP card found (i/o = 0x%x).\n", io[this_dev]); - if (found != 0) { /* Got at least one. */ - return 0; + dev = alloc_ei_netdev(); + if (!dev) + break; + dev->irq = irq[this_dev]; + dev->base_addr = io[this_dev]; + if (do_hp_probe(dev) == 0) { + if (register_netdev(dev) == 0) { + dev_hp[found++] = dev; + continue; } - return -ENXIO; + cleanup_card(dev); } - found++; + free_netdev(dev); + printk(KERN_WARNING "hp.c: No HP card found (i/o = 0x%x).\n", io[this_dev]); + break; } - return 0; + if (found) + return 0; + return -ENXIO; } void @@ -417,14 +449,11 @@ int this_dev; for (this_dev = 0; this_dev < MAX_HP_CARDS; this_dev++) { - struct net_device *dev = &dev_hp[this_dev]; - if (dev->priv != NULL) { - int ioaddr = dev->base_addr - NIC_OFFSET; - void *priv = dev->priv; - free_irq(dev->irq, dev); - release_region(ioaddr, HP_IO_EXTENT); + struct net_device *dev = dev_hp[this_dev]; + if (dev) { unregister_netdev(dev); - kfree(priv); + cleanup_card(dev); + free_netdev(dev); } } } diff -Nru a/drivers/net/hp100.c b/drivers/net/hp100.c --- a/drivers/net/hp100.c Thu Jan 22 18:59:24 2004 +++ b/drivers/net/hp100.c Thu Jan 22 18:59:24 2004 @@ -118,8 +118,6 @@ #include #include -typedef struct net_device_stats hp100_stats_t; - #include "hp100.h" /* @@ -130,23 +128,8 @@ #define HP100_BUS_EISA 1 #define HP100_BUS_PCI 2 -#ifndef PCI_DEVICE_ID_HP_J2585B -#define PCI_DEVICE_ID_HP_J2585B 0x1031 -#endif -#ifndef PCI_VENDOR_ID_COMPEX -#define PCI_VENDOR_ID_COMPEX 0x11f6 -#endif -#ifndef PCI_DEVICE_ID_COMPEX_ENET100VG4 -#define PCI_DEVICE_ID_COMPEX_ENET100VG4 0x0112 -#endif -#ifndef PCI_VENDOR_ID_COMPEX2 -#define PCI_VENDOR_ID_COMPEX2 0x101a -#endif -#ifndef PCI_DEVICE_ID_COMPEX2_100VG -#define PCI_DEVICE_ID_COMPEX2_100VG 0x0005 -#endif - #define HP100_REGION_SIZE 0x20 /* for ioports */ +#define HP100_SIG_LEN 8 /* same as EISA_SIG_LEN */ #define HP100_MAX_PACKET_SIZE (1536+4) #define HP100_MIN_PACKET_SIZE 60 @@ -165,20 +148,9 @@ * structures */ -struct hp100_eisa_id { - u_int id; - const char *name; - u_char bus; -}; - -struct hp100_pci_id { - u_short vendor; - u_short device; -}; - struct hp100_private { - struct hp100_eisa_id *id; spinlock_t lock; + char id[HP100_SIG_LEN]; u_short chip; u_short soft_model; u_int memory_size; @@ -196,7 +168,7 @@ u_char mac1_mode; u_char mac2_mode; u_char hash_bytes[8]; - hp100_stats_t stats; + struct net_device_stats stats; /* Rings for busmaster mode: */ hp100_ring_t *rxrhead; /* Head (oldest) index into rxring */ @@ -216,83 +188,36 @@ /* * variables */ - -static struct hp100_eisa_id hp100_eisa_ids[] = { - - /* 10/100 EISA card with revision A Cascade chip */ - {0x80F1F022, "HP J2577 rev A", HP100_BUS_EISA}, - - /* 10/100 ISA card with revision A Cascade chip */ - {0x50F1F022, "HP J2573 rev A", HP100_BUS_ISA}, - - /* 10 only EISA card with Cascade chip */ - {0x2019F022, "HP 27248B", HP100_BUS_EISA}, - - /* 10/100 EISA card with Cascade chip */ - {0x4019F022, "HP J2577", HP100_BUS_EISA}, - - /* 10/100 ISA card with Cascade chip */ - {0x5019F022, "HP J2573", HP100_BUS_ISA}, - - /* 10/100 EISA card with AT&T chip */ - {0x9019f022, "HP J2577", HP100_BUS_EISA }, - - /* 10/100 PCI card - old J2585A */ - {0x1030103c, "HP J2585A", HP100_BUS_PCI}, - - /* 10/100 PCI card - new J2585B - master capable */ - {0x1041103c, "HP J2585B", HP100_BUS_PCI}, - - /* 10 Mbit Combo Adapter */ - {0x1042103c, "HP J2970", HP100_BUS_PCI}, - - /* 10 Mbit 10baseT Adapter */ - {0x1040103c, "HP J2973", HP100_BUS_PCI}, - - /* 10/100 EISA card from Compex */ - {0x0103180e, "ReadyLink ENET100-VG4", HP100_BUS_EISA}, - - /* 10/100 EISA card from Compex - FreedomLine (sq5bpf) */ - /* Note: plhbrod@mbox.vol.cz reported that same ID have ISA */ - /* version of adapter, too... */ - {0x0104180e, "FreedomLine 100/VG", HP100_BUS_EISA}, - - /* 10/100 PCI card from Compex - FreedomLine - * - * I think this card doesn't like aic7178 scsi controller, but - * I haven't tested this much. It works fine on diskless machines. - * Jacek Lipkowski - */ - {0x021211f6, "FreedomLine 100/VG", HP100_BUS_PCI}, - - /* 10/100 PCI card from Compex (J2585A compatible) */ - {0x011211f6, "ReadyLink ENET100-VG4", HP100_BUS_PCI}, - - /* 10/100 PCI card from KTI */ - {0x40008e2e, "KTI DP-200", HP100_BUS_PCI } +static const char *hp100_isa_tbl[] = { + "HWPF150", /* HP J2573 rev A */ + "HWP1950", /* HP J2573 */ }; -#define HP100_EISA_IDS_SIZE (sizeof(hp100_eisa_ids)/sizeof(struct hp100_eisa_id)) - -#ifdef CONFIG_PCI -static struct hp100_pci_id hp100_pci_ids[] = { - {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_J2585A}, - {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_J2585B}, - {PCI_VENDOR_ID_COMPEX, PCI_DEVICE_ID_COMPEX_ENET100VG4}, - {PCI_VENDOR_ID_COMPEX2, PCI_DEVICE_ID_COMPEX2_100VG} +#ifdef CONFIG_EISA +static struct eisa_device_id hp100_eisa_tbl[] = { + { "HWPF180" }, /* HP J2577 rev A */ + { "HWP1920" }, /* HP 27248B */ + { "HWP1940" }, /* HP J2577 */ + { "HWP1990" }, /* HP J2577 */ + { "CPX0301" }, /* ReadyLink ENET100-VG4 */ + { "CPX0401" }, /* FreedomLine 100/VG */ }; +MODULE_DEVICE_TABLE(eisa, hp100_eisa_tbl); #endif -#define HP100_PCI_IDS_SIZE (sizeof(hp100_pci_ids)/sizeof(struct hp100_pci_id)) - +#ifdef CONFIG_PCI static struct pci_device_id hp100_pci_tbl[] = { {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_J2585A, PCI_ANY_ID, PCI_ANY_ID,}, {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_J2585B, PCI_ANY_ID, PCI_ANY_ID,}, + {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_J2970A, PCI_ANY_ID, PCI_ANY_ID,}, + {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_J2973A, PCI_ANY_ID, PCI_ANY_ID,}, {PCI_VENDOR_ID_COMPEX, PCI_DEVICE_ID_COMPEX_ENET100VG4, PCI_ANY_ID, PCI_ANY_ID,}, {PCI_VENDOR_ID_COMPEX2, PCI_DEVICE_ID_COMPEX2_100VG, PCI_ANY_ID, PCI_ANY_ID,}, +/* {PCI_VENDOR_ID_KTI, PCI_DEVICE_ID_KTI_DP200, PCI_ANY_ID, PCI_ANY_ID }, */ {} /* Terminating entry */ }; MODULE_DEVICE_TABLE(pci, hp100_pci_tbl); +#endif static int hp100_rx_ratio = HP100_DEFAULT_RX_RATIO; static int hp100_priority_tx = HP100_DEFAULT_PRIORITY_TX; @@ -316,7 +241,7 @@ static int hp100_start_xmit_bm(struct sk_buff *skb, struct net_device *dev); static void hp100_rx(struct net_device *dev); -static hp100_stats_t *hp100_get_stats(struct net_device *dev); +static struct net_device_stats *hp100_get_stats(struct net_device *dev); static void hp100_misc_interrupt(struct net_device *dev); static void hp100_update_stats(struct net_device *dev); static void hp100_clear_stats(struct hp100_private *lp, int ioaddr); @@ -370,196 +295,180 @@ * since this could cause problems when the card is not installed. */ -int __init hp100_probe(struct net_device *dev) +/* + * Read board id and convert to string. + * Effectively same code as decode_eisa_sig + */ +static __init const char *hp100_read_id(int ioaddr) { - int base_addr = dev ? dev->base_addr : 0; - int ioaddr = 0; - int pci_start_index = 0; + int i; + static char str[HP100_SIG_LEN]; + unsigned char sig[4], sum; + unsigned short rev; -#ifdef HP100_DEBUG_B - hp100_outw(0x4200, TRACE); - printk("hp100: %s: probe\n", dev->name); -#endif + hp100_page(ID_MAC_ADDR); + sum = 0; + for (i = 0; i < 4; i++) { + sig[i] = hp100_inb(BOARD_ID + i); + sum += sig[i]; + } - if (base_addr > 0xff) { /* Check a single specified location. */ - if (check_region(base_addr, HP100_REGION_SIZE)) - return -EINVAL; - if (base_addr < 0x400) - return hp100_probe1(dev, base_addr, HP100_BUS_ISA, - NULL); - if (EISA_bus && base_addr >= 0x1c38 && ((base_addr - 0x1c38) & 0x3ff) == 0) - return hp100_probe1(dev, base_addr, HP100_BUS_EISA, NULL); -#ifdef CONFIG_PCI - printk("hp100: %s: You must specify card # in i/o address parameter for PCI bus...", dev->name); -#else - return -ENODEV; -#endif - } else -#ifdef CONFIG_PCI - if (base_addr > 0 && base_addr < 8 + 1) - pci_start_index = 0x100 | (base_addr - 1); - else -#endif - if (base_addr != 0) - return -ENXIO; + sum += hp100_inb(BOARD_ID + i); + if (sum != 0xff) + return NULL; /* bad checksum */ - /* First: scan PCI bus(es) */ + str[0] = ((sig[0] >> 2) & 0x1f) + ('A' - 1); + str[1] = (((sig[0] & 3) << 3) | (sig[1] >> 5)) + ('A' - 1); + str[2] = (sig[1] & 0x1f) + ('A' - 1); + rev = (sig[2] << 8) | sig[3]; + sprintf(str + 3, "%04X", rev); -#ifdef CONFIG_PCI - { - int pci_index; - struct pci_dev *pci_dev = NULL; - int pci_id_index; - u_short pci_command; - -#ifdef HP100_DEBUG_PCI - printk("hp100: %s: PCI BIOS is present, checking for devices..\n", dev->name); -#endif - pci_index = 0; - for (pci_id_index = 0; pci_id_index < HP100_PCI_IDS_SIZE; - pci_id_index++) { - while ((pci_dev = pci_find_device(hp100_pci_ids[pci_id_index].vendor, - hp100_pci_ids[pci_id_index].device, - pci_dev)) != NULL) { - if (pci_index < (pci_start_index & 7)) { - pci_index++; - continue; - } - if (pci_enable_device(pci_dev)) - continue; - /* found... */ - ioaddr = pci_resource_start(pci_dev, 0); - if (check_region(ioaddr, HP100_REGION_SIZE)) - continue; - pci_read_config_word(pci_dev, PCI_COMMAND, &pci_command); - if (!(pci_command & PCI_COMMAND_IO)) { -#ifdef HP100_DEBUG - printk("hp100: %s: PCI I/O Bit has not been set. Setting...\n", dev->name); -#endif - pci_command |= PCI_COMMAND_IO; - pci_write_config_word(pci_dev, PCI_COMMAND, pci_command); - } - if (!(pci_command & PCI_COMMAND_MASTER)) { -#ifdef HP100_DEBUG - printk("hp100: %s: PCI Master Bit has not been set. Setting...\n", dev->name); -#endif - pci_command |= PCI_COMMAND_MASTER; - pci_write_config_word(pci_dev, PCI_COMMAND, pci_command); - } -#ifdef HP100_DEBUG - printk("hp100: %s: PCI adapter found at 0x%x\n", dev->name, ioaddr); -#endif - if (hp100_probe1(dev, ioaddr, HP100_BUS_PCI, pci_dev) == 0) - return 0; - } - } - } - if (pci_start_index > 0) - return -ENODEV; -#endif /* CONFIG_PCI */ + return str; +} - /* Second: Probe all EISA possible port regions (if EISA bus present) */ - for (ioaddr = 0x1c38; EISA_bus && ioaddr < 0x10000; ioaddr += 0x400) { - if (check_region(ioaddr, HP100_REGION_SIZE)) - continue; - if (hp100_probe1(dev, ioaddr, HP100_BUS_EISA, NULL) == 0) - return 0; - } +static __init int hp100_isa_probe1(struct net_device *dev, int addr) +{ + const char *sig; + int i; + + if (!request_region(addr, HP100_REGION_SIZE, "hp100")) + goto err; + + sig = hp100_read_id(addr); + release_region(addr, HP100_REGION_SIZE); + + if (sig == NULL) + goto err; + + for (i = 0; i < ARRAY_SIZE(hp100_isa_tbl); i++) { + if (!strcmp(hp100_isa_tbl[i], sig)) + break; - /* Third: Probe all ISA possible port regions */ - for (ioaddr = 0x100; ioaddr < 0x400; ioaddr += 0x20) { - if (check_region(ioaddr, HP100_REGION_SIZE)) - continue; - if (hp100_probe1(dev, ioaddr, HP100_BUS_ISA, NULL) == 0) - return 0; } + if (i < ARRAY_SIZE(hp100_isa_tbl)) + return hp100_probe1(dev, addr, HP100_BUS_ISA, NULL); + err: return -ENODEV; + +} +/* + * Probe for ISA board. + * EISA and PCI are handled by device infrastructure. + */ + +static int __init hp100_isa_probe(struct net_device *dev, int addr) +{ + int err = -ENODEV; + + /* Probe for a specific ISA address */ + if (addr > 0xff && addr < 0x400) + err = hp100_isa_probe1(dev, addr); + + else if (addr != 0) + err = -ENXIO; + + else { + /* Probe all ISA possible port regions */ + for (addr = 0x100; addr < 0x400; addr += 0x20) { + err = hp100_isa_probe1(dev, addr); + if (!err) + break; + } + } + return err; +} + + +struct net_device * __init hp100_probe(int unit) +{ + struct net_device *dev = alloc_etherdev(sizeof(struct hp100_private)); + int err; + + if (!dev) + return ERR_PTR(-ENODEV); + + SET_MODULE_OWNER(dev); + +#ifdef HP100_DEBUG_B + hp100_outw(0x4200, TRACE); + printk("hp100: %s: probe\n", dev->name); +#endif + + if (unit >= 0) { + sprintf(dev->name, "eth%d", unit); + netdev_boot_setup_check(dev); + } + + err = hp100_isa_probe(dev, dev->base_addr); + if (err) + goto out; + + err = register_netdev(dev); + if (err) + goto out1; + return dev; + out1: + release_region(dev->base_addr, HP100_REGION_SIZE); + out: + free_netdev(dev); + return ERR_PTR(err); } static int __init hp100_probe1(struct net_device *dev, int ioaddr, u_char bus, struct pci_dev *pci_dev) { int i; - - u_char uc, uc_1; - u_int eisa_id; + int err = -ENODEV; + const char *eid; u_int chip; + u_char uc; u_int memory_size = 0, virt_memory_size = 0; u_short local_mode, lsw; short mem_mapped; unsigned long mem_ptr_phys; void **mem_ptr_virt; struct hp100_private *lp; - struct hp100_eisa_id *eid; #ifdef HP100_DEBUG_B hp100_outw(0x4201, TRACE); printk("hp100: %s: probe1\n", dev->name); #endif - if (dev == NULL) { -#ifdef HP100_DEBUG - printk("hp100_probe1: %s: dev == NULL ?\n", dev->name); -#endif - return -EIO; - } + /* memory region for programmed i/o */ + if (!request_region(ioaddr, HP100_REGION_SIZE, "hp100")) + goto out1; - if (hp100_inw(HW_ID) != HP100_HW_ID_CASCADE) { - return -ENODEV; - } else { - chip = hp100_inw(PAGING) & HP100_CHIPID_MASK; + if (hp100_inw(HW_ID) != HP100_HW_ID_CASCADE) + goto out2; + + chip = hp100_inw(PAGING) & HP100_CHIPID_MASK; #ifdef HP100_DEBUG - if (chip == HP100_CHIPID_SHASTA) - printk("hp100: %s: Shasta Chip detected. (This is a pre 802.12 chip)\n", dev->name); - else if (chip == HP100_CHIPID_RAINIER) - printk("hp100: %s: Rainier Chip detected. (This is a pre 802.12 chip)\n", dev->name); - else if (chip == HP100_CHIPID_LASSEN) - printk("hp100: %s: Lassen Chip detected.\n", dev->name); - else - printk("hp100: %s: Warning: Unknown CASCADE chip (id=0x%.4x).\n", dev->name, chip); + if (chip == HP100_CHIPID_SHASTA) + printk("hp100: %s: Shasta Chip detected. (This is a pre 802.12 chip)\n", dev->name); + else if (chip == HP100_CHIPID_RAINIER) + printk("hp100: %s: Rainier Chip detected. (This is a pre 802.12 chip)\n", dev->name); + else if (chip == HP100_CHIPID_LASSEN) + printk("hp100: %s: Lassen Chip detected.\n", dev->name); + else + printk("hp100: %s: Warning: Unknown CASCADE chip (id=0x%.4x).\n", dev->name, chip); #endif - } dev->base_addr = ioaddr; - hp100_page(ID_MAC_ADDR); - for (i = uc = eisa_id = 0; i < 4; i++) { - eisa_id >>= 8; - uc_1 = hp100_inb(BOARD_ID + i); - eisa_id |= uc_1 << 24; - uc += uc_1; - } - uc += hp100_inb(BOARD_ID + 4); - - if (uc != 0xff) { /* bad checksum? */ - printk("hp100_probe: %s: bad EISA ID checksum at base port 0x%x\n", dev->name, ioaddr); - return -ENODEV; - } - - for (i = 0; i < HP100_EISA_IDS_SIZE; i++) - if (hp100_eisa_ids[i].id == eisa_id) - break; - if (i >= HP100_EISA_IDS_SIZE) { - for (i = 0; i < HP100_EISA_IDS_SIZE; i++) - if ((hp100_eisa_ids[i].id & 0xf0ffffff) == (eisa_id & 0xf0ffffff)) - break; - if (i >= HP100_EISA_IDS_SIZE) { - printk ("hp100_probe: %s: card at port 0x%x isn't known (id = 0x%x)\n", dev->name, ioaddr, eisa_id); - return -ENODEV; - } - } - eid = &hp100_eisa_ids[i]; - if ((eid->id & 0x0f000000) < (eisa_id & 0x0f000000)) { - printk("hp100_probe: %s: newer version of card %s at port 0x%x - unsupported\n", dev->name, eid->name, ioaddr); - return -ENODEV; + eid = hp100_read_id(ioaddr); + if (eid == NULL) { /* bad checksum? */ + printk(KERN_WARNING "hp100_probe: bad ID checksum at base port 0x%x\n", ioaddr); + goto out2; } + hp100_page(ID_MAC_ADDR); for (i = uc = 0; i < 7; i++) uc += hp100_inb(LAN_ADDR + i); if (uc != 0xff) { - printk("hp100_probe: %s: bad lan address checksum (card %s at port 0x%x)\n", dev->name, eid->name, ioaddr); - return -EIO; + printk(KERN_WARNING "hp100_probe: bad lan address checksum at port 0x%x)\n", ioaddr); + err = -EIO; + goto out2; } /* Make sure, that all registers are correctly updated... */ @@ -607,17 +516,17 @@ hp100_outw(HP100_MEM_EN | HP100_RESET_LB, OPTION_LSW); hp100_outw(HP100_IO_EN | HP100_SET_LB, OPTION_LSW); hp100_outw(HP100_BM_WRITE | HP100_BM_READ | HP100_RESET_HB, OPTION_LSW); - printk("hp100: %s: IO mapped mode forced.\n", dev->name); + printk("hp100: IO mapped mode forced.\n"); } else if (local_mode == 2) { hp100_outw(HP100_MEM_EN | HP100_SET_LB, OPTION_LSW); hp100_outw(HP100_IO_EN | HP100_SET_LB, OPTION_LSW); hp100_outw(HP100_BM_WRITE | HP100_BM_READ | HP100_RESET_HB, OPTION_LSW); - printk("hp100: %s: Shared memory mode requested.\n", dev->name); + printk("hp100: Shared memory mode requested.\n"); } else if (local_mode == 4) { if (chip == HP100_CHIPID_LASSEN) { hp100_outw(HP100_BM_WRITE | HP100_BM_READ | HP100_SET_HB, OPTION_LSW); hp100_outw(HP100_IO_EN | HP100_MEM_EN | HP100_RESET_LB, OPTION_LSW); - printk("hp100: %s: Busmaster mode requested.\n", dev->name); + printk("hp100: Busmaster mode requested.\n"); } local_mode = 1; } @@ -643,7 +552,7 @@ /* Gracefully fallback to shared memory */ goto busmasterfail; } - printk("hp100: %s: Busmaster mode enabled.\n", dev->name); + printk("hp100: Busmaster mode enabled.\n"); hp100_outw(HP100_MEM_EN | HP100_IO_EN | HP100_RESET_LB, OPTION_LSW); } else { busmasterfail: @@ -675,7 +584,7 @@ mem_ptr_phys &= ~0x1fff; /* 8k alignment */ if (bus == HP100_BUS_ISA && (mem_ptr_phys & ~0xfffff) != 0) { - printk("hp100: %s: Can only use programmed i/o mode.\n", dev->name); + printk("hp100: Can only use programmed i/o mode.\n"); mem_ptr_phys = 0; mem_mapped = 0; local_mode = 3; /* Use programmed i/o */ @@ -699,7 +608,7 @@ } if (mem_ptr_virt == NULL) { /* all ioremap tries failed */ - printk("hp100: %s: Failed to ioremap the PCI card memory. Will have to use i/o mapped mode.\n", dev->name); + printk("hp100: Failed to ioremap the PCI card memory. Will have to use i/o mapped mode.\n"); local_mode = 3; virt_memory_size = 0; } @@ -710,17 +619,14 @@ mem_mapped = 0; mem_ptr_phys = 0; mem_ptr_virt = NULL; - printk("hp100: %s: Using (slow) programmed i/o mode.\n", dev->name); + printk("hp100: Using (slow) programmed i/o mode.\n"); } /* Initialise the "private" data structure for this card. */ - if ((dev->priv = kmalloc(sizeof(struct hp100_private), GFP_KERNEL)) == NULL) - return -ENOMEM; - lp = (struct hp100_private *) dev->priv; - memset(lp, 0, sizeof(struct hp100_private)); + spin_lock_init(&lp->lock); - lp->id = eid; + strlcpy(lp->id, eid, HP100_SIG_LEN); lp->chip = chip; lp->mode = local_mode; lp->bus = bus; @@ -741,9 +647,6 @@ lp->virt_memory_size = virt_memory_size; lp->rx_ratio = hp100_rx_ratio; /* can be conf'd with insmod */ - /* memory region for programmed i/o */ - request_region(dev->base_addr, HP100_REGION_SIZE, eid->name); - dev->open = hp100_open; dev->stop = hp100_close; @@ -776,10 +679,6 @@ /* Reset statistics (counters) */ hp100_clear_stats(lp, ioaddr); - SET_MODULE_OWNER(dev); - SET_NETDEV_DEV(dev, &pci_dev->dev); - ether_setup(dev); - /* If busmaster mode is wanted, a dma-capable memory area is needed for * the rx and tx PDLs * PCI cards can access the whole PC memory. Therefore GFP_DMA is not @@ -795,8 +694,10 @@ /* Conversion to new PCI API : * Pages are always aligned and zeroed, no need to it ourself. * Doc says should be OK for EISA bus as well - Jean II */ - if ((lp->page_vaddr_algn = pci_alloc_consistent(lp->pci_dev, MAX_RINGSIZE, &page_baddr)) == NULL) - return -ENOMEM; + if ((lp->page_vaddr_algn = pci_alloc_consistent(lp->pci_dev, MAX_RINGSIZE, &page_baddr)) == NULL) { + err = -ENOMEM; + goto out2; + } lp->whatever_offset = ((u_long) page_baddr) - ((u_long) lp->page_vaddr_algn); #ifdef HP100_DEBUG_BM @@ -818,7 +719,7 @@ lp->lan_type = hp100_sense_lan(dev); /* Print out a message what about what we think we have probed. */ - printk("hp100: %s: %s at 0x%x, IRQ %d, ", dev->name, lp->id->name, ioaddr, dev->irq); + printk("hp100: at 0x%x, IRQ %d, ", ioaddr, dev->irq); switch (bus) { case HP100_BUS_EISA: printk("EISA"); @@ -833,7 +734,7 @@ printk(" bus, %dk SRAM (rx/tx %d%%).\n", lp->memory_size >> 10, lp->rx_ratio); if (lp->mode == 2) { /* memory mapped */ - printk("hp100: %s: Memory area at 0x%lx-0x%lx", dev->name, mem_ptr_phys, + printk("hp100: Memory area at 0x%lx-0x%lx", mem_ptr_phys, (mem_ptr_phys + (mem_ptr_phys > 0x100000 ? (u_long) lp->memory_size : 16 * 1024)) - 1); if (mem_ptr_virt) printk(" (virtual base %p)", mem_ptr_virt); @@ -843,7 +744,8 @@ dev->mem_start = mem_ptr_phys; dev->mem_end = mem_ptr_phys + lp->memory_size; } - printk("hp100: %s: ", dev->name); + + printk("hp100: "); if (lp->lan_type != HP100_LAN_ERR) printk("Adapter is attached to "); switch (lp->lan_type) { @@ -861,6 +763,10 @@ } return 0; +out2: + release_region(ioaddr, HP100_REGION_SIZE); +out1: + return -ENODEV; } /* This procedure puts the card into a stable init state */ @@ -950,6 +856,7 @@ /* Finally try to log in the Hub if there may be a VG connection. */ if ((lp->lan_type == HP100_LAN_100) || (lp->lan_type == HP100_LAN_ERR)) hp100_login_to_vg_hub(dev, 0); /* relogin */ + } @@ -1152,7 +1059,7 @@ if (request_irq(dev->irq, hp100_interrupt, lp->bus == HP100_BUS_PCI || lp->bus == HP100_BUS_EISA ? SA_SHIRQ : SA_INTERRUPT, - lp->id->name, dev)) { + "hp100", dev)) { printk("hp100: %s: unable to get IRQ %d\n", dev->name, dev->irq); return -EAGAIN; } @@ -2054,7 +1961,7 @@ /* * statistics */ -static hp100_stats_t *hp100_get_stats(struct net_device *dev) +static struct net_device_stats *hp100_get_stats(struct net_device *dev) { unsigned long flags; int ioaddr = dev->base_addr; @@ -2558,10 +2465,14 @@ return HP100_LAN_COAX; } - if ((lp->id->id == 0x02019F022) || - (lp->id->id == 0x01042103c) || (lp->id->id == 0x01040103c)) - return HP100_LAN_ERR; /* Those cards don't have a 100 Mbit connector */ - + /* Those cards don't have a 100 Mbit connector */ + if ( !strcmp(lp->id, "HWP1920") || + (lp->pci_dev && + lp->pci_dev->vendor == PCI_VENDOR_ID && + (lp->pci_dev->device == PCI_DEVICE_ID_HP_J2970A || + lp->pci_dev->device == PCI_DEVICE_ID_HP_J2973A))) + return HP100_LAN_ERR; + if (val_VG & HP100_LINK_CABLE_ST) /* Can hear the HUBs tone. */ return HP100_LAN_100; return HP100_LAN_ERR; @@ -2915,121 +2826,247 @@ #endif +static void cleanup_dev(struct net_device *d) +{ + struct hp100_private *p = (struct hp100_private *) d->priv; + + unregister_netdev(d); + release_region(d->base_addr, HP100_REGION_SIZE); + + if (p->mode == 1) /* busmaster */ + pci_free_consistent(p->pci_dev, MAX_RINGSIZE + 0x0f, + p->page_vaddr_algn, + virt_to_whatever(d, p->page_vaddr_algn)); + if (p->mem_ptr_virt) + iounmap(p->mem_ptr_virt); + + free_netdev(d); +} + +#ifdef CONFIG_EISA +static int __init hp100_eisa_probe (struct device *gendev) +{ + struct net_device *dev = alloc_etherdev(sizeof(struct hp100_private)); + struct eisa_device *edev = to_eisa_device(gendev); + int err; + + if (!dev) + return -ENOMEM; + + SET_MODULE_OWNER(dev); + SET_NETDEV_DEV(dev, &edev->dev); + + err = hp100_probe1(dev, edev->base_addr, HP100_BUS_EISA, NULL); + if (err) + goto out1; + + err = register_netdev(dev); + if (err) + goto out2; + +#ifdef HP100_DEBUG + printk("hp100: %s: EISA adapter found at 0x%x\n", dev->name, + dev->base_addr); +#endif + gendev->driver_data = dev; + return 0; + out2: + release_region(dev->base_addr, HP100_REGION_SIZE); + out1: + free_netdev(dev); + return err; +} + +static int __devexit hp100_eisa_remove (struct device *gendev) +{ + struct net_device *dev = gendev->driver_data; + cleanup_dev(dev); + return 0; +} + +static struct eisa_driver hp100_eisa_driver = { + .id_table = hp100_eisa_tbl, + .driver = { + .name = "hp100", + .probe = hp100_eisa_probe, + .remove = __devexit_p (hp100_eisa_remove), + } +}; +#endif + +#ifdef CONFIG_PCI +static int __devinit hp100_pci_probe (struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + struct net_device *dev = alloc_etherdev(sizeof(struct hp100_private)); + int ioaddr = pci_resource_start(pdev, 0); + u_short pci_command; + int err; + + if (!dev) + return -ENOMEM; + + SET_MODULE_OWNER(dev); + SET_NETDEV_DEV(dev, &pdev->dev); + + pci_read_config_word(pdev, PCI_COMMAND, &pci_command); + if (!(pci_command & PCI_COMMAND_IO)) { +#ifdef HP100_DEBUG + printk("hp100: %s: PCI I/O Bit has not been set. Setting...\n", dev->name); +#endif + pci_command |= PCI_COMMAND_IO; + pci_write_config_word(pdev, PCI_COMMAND, pci_command); + } + + if (!(pci_command & PCI_COMMAND_MASTER)) { +#ifdef HP100_DEBUG + printk("hp100: %s: PCI Master Bit has not been set. Setting...\n", dev->name); +#endif + pci_command |= PCI_COMMAND_MASTER; + pci_write_config_word(pdev, PCI_COMMAND, pci_command); + } + + + err = hp100_probe1(dev, ioaddr, HP100_BUS_PCI, pdev); + if (err) + goto out1; + err = register_netdev(dev); + if (err) + goto out2; + +#ifdef HP100_DEBUG + printk("hp100: %s: PCI adapter found at 0x%x\n", dev->name, ioaddr); +#endif + pci_set_drvdata(pdev, dev); + return 0; + out2: + release_region(dev->base_addr, HP100_REGION_SIZE); + out1: + free_netdev(dev); + return err; +} + +static void __devexit hp100_pci_remove (struct pci_dev *pdev) +{ + struct net_device *dev = pci_get_drvdata(pdev); + + cleanup_dev(dev); +} + + +static struct pci_driver hp100_pci_driver = { + .name = "hp100", + .id_table = hp100_pci_tbl, + .probe = hp100_pci_probe, + .remove = __devexit_p(hp100_pci_remove), +}; +#endif + /* * module section */ -#ifdef MODULE - MODULE_LICENSE("GPL"); MODULE_AUTHOR("Jaroslav Kysela , " "Siegfried \"Frieder\" Loeffler (dg1sek) "); MODULE_DESCRIPTION("HP CASCADE Architecture Driver for 100VG-AnyLan Network Adapters"); /* - * Note: if you have more than five 100vg cards in your pc, feel free to - * increase this value - */ - -#define HP100_DEVICES 5 - -/* - * Note: to register three eisa or pci devices, use: + * Note: to register three isa devices, use: * option hp100 hp100_port=0,0,0 * to register one card at io 0x280 as eth239, use: - * option hp100 hp100_port=0x280 hp100_name=eth239 + * option hp100 hp100_port=0x280 */ - +#if defined(MODULE) && defined(CONFIG_ISA) +#define HP100_DEVICES 5 /* Parameters set by insmod */ static int hp100_port[HP100_DEVICES] = { 0, [1 ... (HP100_DEVICES-1)] = -1 }; MODULE_PARM(hp100_port, "1-" __MODULE_STRING(HP100_DEVICES) "i"); -/* Allocate HP100_DEVICES strings of length IFNAMSIZ, one string for each device */ -static char hp100_name[HP100_DEVICES][IFNAMSIZ] = { "", "", "", "", "" }; -/* Allow insmod to write those HP100_DEVICES strings individually */ -MODULE_PARM(hp100_name, "1-" __MODULE_STRING(HP100_DEVICES) "c" __MODULE_STRING(IFNAMSIZ)); - /* List of devices */ static struct net_device *hp100_devlist[HP100_DEVICES]; -static void release_dev(int i) +static int __init hp100_isa_init(void) { - struct net_device *d = hp100_devlist[i]; - struct hp100_private *p = (struct hp100_private *) d->priv; + struct net_device *dev; + int i, err, cards = 0; - unregister_netdev(d); - release_region(d->base_addr, HP100_REGION_SIZE); + /* Don't autoprobe ISA bus */ + if (hp100_port[0] == 0) + return -ENODEV; - if (p->mode == 1) /* busmaster */ - pci_free_consistent(p->pci_dev, MAX_RINGSIZE + 0x0f, p->page_vaddr_algn, virt_to_whatever(d, p->page_vaddr_algn)); - if (p->mem_ptr_virt) - iounmap(p->mem_ptr_virt); - kfree(d->priv); - d->priv = NULL; - free_netdev(d); - hp100_devlist[i] = NULL; + /* Loop on all possible base addresses */ + for (i = 0; i < HP100_DEVICES && hp100_port[i] != -1; ++i) { + dev = alloc_etherdev(sizeof(struct hp100_private)); + if (!dev) { + printk(KERN_WARNING "hp100: no memory for network device\n"); + while (cards > 0) + cleanup_dev(hp100_devlist[--cards]); + + return -ENOMEM; + } + SET_MODULE_OWNER(dev); + + err = hp100_isa_probe(dev, hp100_port[i]); + if (!err) { + err = register_netdev(dev); + if (!err) + hp100_devlist[cards++] = dev; + else + release_region(dev->base_addr, HP100_REGION_SIZE); + } + + if (err) + free_netdev(dev); + } + + return cards > 0 ? 0 : -ENODEV; } -static int __init hp100_module_init(void) +static void __exit hp100_isa_cleanup(void) { - int i, cards; + int i; -#ifndef CONFIG_PCI - if (hp100_port == 0 && !EISA_bus) - printk("hp100: You should not use auto-probing with insmod!\n"); + for (i = 0; i < HP100_DEVICES; i++) { + struct net_device *dev = hp100_devlist[i]; + if (dev) + cleanup_dev(dev); + } +} +#else +#define hp100_isa_init() (0) +#define hp100_isa_cleanup() do { } while(0) #endif - /* Loop on all possible base addresses */ - i = -1; - cards = 0; - while ((hp100_port[++i] != -1) && (i < HP100_DEVICES)) { - /* Create device and set basics args */ - hp100_devlist[i] = kmalloc(sizeof(struct net_device), GFP_KERNEL); - if (!hp100_devlist[i]) - goto fail; - memset(hp100_devlist[i], 0x00, sizeof(struct net_device)); -#if LINUX_VERSION_CODE >= 0x020362 /* 2.3.99-pre7 */ - memcpy(hp100_devlist[i]->name, hp100_name[i], IFNAMSIZ); /* Copy name */ -#else - hp100_devlist[i]->name = hp100_name[i]; -#endif /* LINUX_VERSION_CODE >= 0x020362 */ - hp100_devlist[i]->base_addr = hp100_port[i]; - hp100_devlist[i]->init = &hp100_probe; - - /* Try to create the device */ - if (register_netdev(hp100_devlist[i]) != 0) { - /* DeAllocate everything */ - /* Note: if dev->priv is mallocated, there is no way to fail */ - kfree(hp100_devlist[i]); - hp100_devlist[i] = (struct net_device *) NULL; - } else - cards++; - } /* Loop over all devices */ +static int __init hp100_module_init(void) +{ + int err; - return cards > 0 ? 0 : -ENODEV; - fail: - while (cards && --i) - if (hp100_devlist[i]) { - release_dev(i); - --cards; - } - return -ENOMEM; + err = hp100_isa_init(); + +#ifdef CONFIG_EISA + err |= eisa_driver_register(&hp100_eisa_driver); +#endif +#ifdef CONFIG_PCI + err |= pci_module_init(&hp100_pci_driver); +#endif + return err; } + static void __exit hp100_module_exit(void) { - int i; - - /* TODO: Check if all skb's are released/freed. */ - for (i = 0; i < HP100_DEVICES; i++) - if (hp100_devlist[i] != (struct net_device *) NULL) - release_dev(i); + hp100_isa_cleanup(); +#ifdef CONFIG_EISA + eisa_driver_unregister (&hp100_eisa_driver); +#endif +#ifdef CONFIG_PCI + pci_unregister_driver (&hp100_pci_driver); +#endif } module_init(hp100_module_init) module_exit(hp100_module_exit) - -#endif /* MODULE */ /* diff -Nru a/drivers/net/hplance.c b/drivers/net/hplance.c --- a/drivers/net/hplance.c Thu Jan 22 18:59:25 2004 +++ b/drivers/net/hplance.c Thu Jan 22 18:59:25 2004 @@ -50,8 +50,7 @@ * plus board-specific init, open and close actions. * Oh, and we need to tell the generic code how to read and write LANCE registers... */ -int hplance_probe(struct net_device *dev); -static int hplance_init(struct net_device *dev, int scode); +static void hplance_init(struct net_device *dev, int scode); static int hplance_open(struct net_device *dev); static int hplance_close(struct net_device *dev); static void hplance_writerap(void *priv, unsigned short value); @@ -62,57 +61,61 @@ static struct hplance_private *root_hplance_dev; #endif +static void cleanup_card(struct net_device *dev) +{ + struct hplance_private *lp = dev->priv; + dio_unconfig_board(lp->scode); +} + /* Find all the HP Lance boards and initialise them... */ -int __init hplance_probe(struct net_device *dev) +struct net_device * __init hplance_probe(int unit) { - int cards = 0, called = 0; + struct net_device *dev; + + if (!MACH_IS_HP300) + return ERR_PTR(-ENODEV); + + dev = alloc_etherdev(sizeof(struct hplance_private)); + if (!dev) + return ERR_PTR(-ENOMEM); + + if (unit >= 0) { + sprintf(dev->name, "eth%d", unit); + netdev_boot_setup_check(dev); + } - if (!MACH_IS_HP300 || called) - return(ENODEV); - called++; + SET_MODULE_OWNER(dev); /* Isn't DIO nice? */ for(;;) { - int v, scode = dio_find(DIO_ID_LAN); + int scode = dio_find(DIO_ID_LAN); if (!scode) break; - if(cards) - dev = NULL; /* don't trash previous device, make a new one */ - cards++; - - v = hplance_init(dev, scode); - if (v) /* error, abort immediately */ - return v; + dio_config_board(scode); + hplance_init(dev, scode); + if (!register_netdev(dev)) { + struct hplance_private *lp = dev->priv; + lp->next_module = root_hplance_dev; + root_hplance_dev = lp; + return dev; + } + cleanup_card(dev); } - /* OK, return success, or ENODEV if we didn't find any cards */ - if (!cards) - return -ENODEV; - return 0; + free_netdev(dev); + return ERR_PTR(-ENODEV); } /* Initialise a single lance board at the given select code */ -static int __init hplance_init(struct net_device *dev, int scode) +static void __init hplance_init(struct net_device *dev, int scode) { const char *name = dio_scodetoname(scode); void *va = dio_scodetoviraddr(scode); struct hplance_private *lp; int i; -#ifdef MODULE - dev = init_etherdev(0, sizeof(struct hplance_private)); - if (!dev) - return -ENOMEM; -#else - dev->priv = kmalloc(sizeof(struct hplance_private), GFP_KERNEL); - if (dev->priv == NULL) - return -ENOMEM; - memset(dev->priv, 0, sizeof(struct hplance_private)); -#endif - SET_MODULE_OWNER(dev); - printk("%s: %s; select code %d, addr", dev->name, name, scode); /* reset the board */ @@ -154,17 +157,7 @@ lp->lance.tx_ring_mod_mask = TX_RING_MOD_MASK; lp->scode = scode; lp->base = va; - ether_setup(dev); printk(", irq %d\n", lp->lance.irq); - -#ifdef MODULE - dev->ifindex = dev_new_index(); - lp->next_module = root_hplance_dev; - root_hplance_dev = lp; -#endif /* MODULE */ - - dio_config_board(scode); /* tell bus scanning code this one's taken */ - return 0; } /* This is disgusting. We have to check the DIO status register for ack every @@ -227,8 +220,10 @@ MODULE_LICENSE("GPL"); int init_module(void) { - root_lance_dev = NULL; - return hplance_probe(NULL); + int found = 0; + while (!IS_ERR(hplance_probe(-1))) + found++; + return found ? 0 : -ENODEV; } void cleanup_module(void) @@ -237,8 +232,8 @@ struct hplance_private *lp; while (root_hplance_dev) { lp = root_hplance_dev->next_module; - dio_unconfig_board(lp->scode); unregister_netdev(root_lance_dev->dev); + cleanup_card(root_lance_dev->dev); free_netdev(root_lance_dev->dev); root_lance_dev = lp; } diff -Nru a/drivers/net/hydra.c b/drivers/net/hydra.c --- a/drivers/net/hydra.c Thu Jan 22 18:59:25 2004 +++ b/drivers/net/hydra.c Thu Jan 22 18:59:25 2004 @@ -89,13 +89,14 @@ const char name[] = "NE2000"; int start_page, stop_page; int j; + int err; static u32 hydra_offsets[16] = { 0x00, 0x02, 0x04, 0x06, 0x08, 0x0a, 0x0c, 0x0e, 0x10, 0x12, 0x14, 0x16, 0x18, 0x1a, 0x1c, 0x1e, }; - dev = init_etherdev(NULL, 0); + dev = alloc_ei_netdev(); if (!dev) return -ENOMEM; SET_MODULE_OWNER(dev); @@ -113,13 +114,9 @@ /* Install the Interrupt handler */ if (request_irq(IRQ_AMIGA_PORTS, ei_interrupt, SA_SHIRQ, "Hydra Ethernet", - dev)) + dev)) { + free_netdev(dev); return -EAGAIN; - - /* Allocate dev->priv and fill in 8390 specific dev fields. */ - if (ethdev_init(dev)) { - printk("Unable to get memory for dev->priv.\n"); - return -ENOMEM; } printk("%s: hydra at 0x%08lx, address %02x:%02x:%02x:%02x:%02x:%02x (hydra.c " HYDRA_VERSION ")\n", dev->name, ZTWO_PADDR(board), @@ -141,12 +138,21 @@ ei_status.reg_offset = hydra_offsets; dev->open = &hydra_open; dev->stop = &hydra_close; +#ifdef CONFIG_NET_POLL_CONTROLLER + dev->poll_controller = ei_poll; +#endif #ifdef MODULE ei_status.priv = (unsigned long)root_hydra_dev; root_hydra_dev = dev; #endif NS8390_init(dev, 0); - return 0; + err = register_netdev(dev); + if (!err) + return 0; + + free_irq(IRQ_AMIGA_PORTS, dev); + free_netdev(dev); + return err; } static int hydra_open(struct net_device *dev) diff -Nru a/drivers/net/ibmlana.c b/drivers/net/ibmlana.c --- a/drivers/net/ibmlana.c Thu Jan 22 18:59:24 2004 +++ b/drivers/net/ibmlana.c Thu Jan 22 18:59:24 2004 @@ -906,7 +906,7 @@ static int startslot; /* counts through slots when probing multiple devices */ -int ibmlana_probe(struct net_device *dev) +static int ibmlana_probe(struct net_device *dev) { int force_detect = 0; int slot, z; @@ -924,34 +924,21 @@ if (dev->mem_start == 1) force_detect = 1; - /* search through slots */ - if (dev != NULL) { - base = dev->mem_start; - irq = dev->irq; - } - slot = mca_find_adapter(IBM_LANA_ID, startslot); + base = dev->mem_start; + irq = dev->irq; - while (slot != -1) { + for (slot = startslot; (slot = mca_find_adapter(IBM_LANA_ID, slot)) != -1; slot++) { /* deduce card addresses */ getaddrs(slot, &base, &memlen, &iobase, &irq, &medium); /* slot already in use ? */ - if (mca_is_adapter_used(slot)) { - slot = mca_find_adapter(IBM_LANA_ID, slot + 1); + if (mca_is_adapter_used(slot)) continue; - } /* were we looking for something different ? */ - if (dev->irq != 0 || dev->mem_start != 0) { - if (dev->irq != 0 && dev->irq != irq) { - slot = mca_find_adapter(IBM_LANA_ID, slot + 1); - continue; - } - if (dev->mem_start != 0 && dev->mem_start != base) - { - slot = mca_find_adapter(IBM_LANA_ID, slot + 1); - continue; - } - } + if (dev->irq && dev->irq != irq) + continue; + if (dev->mem_start && dev->mem_start != base) + continue; /* found something that matches */ break; } @@ -977,16 +964,11 @@ mca_mark_as_used(slot); /* allocate structure */ - priv = dev->priv = (ibmlana_priv *) kmalloc(sizeof(ibmlana_priv), GFP_KERNEL); - if (!priv) { - release_region(iobase, IBM_LANA_IORANGE); - return -ENOMEM; - } + priv = dev->priv; priv->slot = slot; priv->realirq = irq; priv->medium = medium; spin_lock_init(&priv->lock); - memset(&priv->stat, 0, sizeof(struct net_device_stats)); /* set base + irq for this device (irq not allocated so far) */ @@ -1006,10 +988,6 @@ dev->set_multicast_list = ibmlana_set_multicast_list; dev->flags |= IFF_MULTICAST; - /* generic setup */ - - ether_setup(dev); - /* copy out MAC address */ for (z = 0; z < sizeof(dev->dev_addr); z++) @@ -1044,7 +1022,7 @@ #define DEVMAX 5 -static struct net_device moddevs[DEVMAX]; +static struct net_device *moddevs[DEVMAX]; static int irq; static int io; @@ -1056,41 +1034,47 @@ int init_module(void) { - int z, res; + int z; startslot = 0; for (z = 0; z < DEVMAX; z++) { - moddevs[z].init = ibmlana_probe; - moddevs[z].irq = irq; - moddevs[z].base_addr = io; - res = register_netdev(moddevs + z); - if (res != 0) - return (z > 0) ? 0 : -EIO; + struct net_device *dev = alloc_etherdev(sizeof(ibmlana_priv)); + if (!dev) + break; + dev->irq = irq; + dev->base_addr = io; + if (ibmlana_probe(dev)) { + free_netdev(dev); + break; + } + if (register_netdev(dev)) { + ibmlana_priv *priv = dev->priv; + release_region(dev->base_addr, IBM_LANA_IORANGE); + mca_mark_as_unused(priv->slot); + mca_set_adapter_name(priv->slot, ""); + mca_set_adapter_procfn(priv->slot, NULL, NULL); + free_netdev(dev); + break; + } + moddevs[z] = dev; } - return 0; + return (z > 0) ? 0 : -EIO; } void cleanup_module(void) { - struct net_device *dev; - ibmlana_priv *priv; int z; - for (z = 0; z < DEVMAX; z++) { - dev = moddevs + z; - if (dev->priv != NULL) { - priv = (ibmlana_priv *) dev->priv; + struct net_device *dev = moddevs[z]; + if (dev) { + ibmlana_priv *priv = (ibmlana_priv *) dev->priv; + unregister_netdev(dev); /*DeinitBoard(dev); */ - if (dev->irq != 0) - free_irq(dev->irq, dev); - dev->irq = 0; release_region(dev->base_addr, IBM_LANA_IORANGE); - unregister_netdev(dev); mca_mark_as_unused(priv->slot); mca_set_adapter_name(priv->slot, ""); mca_set_adapter_procfn(priv->slot, NULL, NULL); - kfree(dev->priv); - dev->priv = NULL; + free_netdev(dev); } } } diff -Nru a/drivers/net/ibmlana.h b/drivers/net/ibmlana.h --- a/drivers/net/ibmlana.h Thu Jan 22 18:59:26 2004 +++ b/drivers/net/ibmlana.h Thu Jan 22 18:59:26 2004 @@ -275,7 +275,4 @@ #endif /* _IBM_LANA_DRIVER_ */ -extern int ibmlana_probe(struct net_device *); - - #endif /* _IBM_LANA_INCLUDE_ */ diff -Nru a/drivers/net/irda/sa1100_ir.c b/drivers/net/irda/sa1100_ir.c --- a/drivers/net/irda/sa1100_ir.c Thu Jan 22 18:59:24 2004 +++ b/drivers/net/irda/sa1100_ir.c Thu Jan 22 18:59:24 2004 @@ -20,6 +20,7 @@ */ #include #include +#include #include #include #include @@ -358,9 +359,13 @@ static int sa1100_irda_suspend(struct device *_dev, u32 state, u32 level) { struct net_device *dev = dev_get_drvdata(_dev); - struct sa1100_irda *si = dev->priv; + struct sa1100_irda *si; + + if (!dev || level != SUSPEND_DISABLE) + return 0; - if (si && si->open && level == SUSPEND_DISABLE) { + si = dev->priv; + if (si->open) { /* * Stop the transmit queue */ @@ -379,9 +384,13 @@ static int sa1100_irda_resume(struct device *_dev, u32 level) { struct net_device *dev = dev_get_drvdata(_dev); - struct sa1100_irda *si = dev->priv; + struct sa1100_irda *si; - if (si && si->open && level == RESUME_ENABLE) { + if (!dev || level != RESUME_ENABLE) + return 0; + + si = dev->priv; + if (si->open) { /* * If we missed a speed change, initialise at the new speed * directly. It is debatable whether this is actually @@ -833,8 +842,6 @@ struct sa1100_irda *si = dev->priv; int err; - MOD_INC_USE_COUNT; - si->speed = 9600; err = request_irq(dev->irq, sa1100_irda_irq, 0, dev->name, dev); @@ -890,7 +897,6 @@ err_rx_dma: free_irq(dev->irq, dev); err_irq: - MOD_DEC_USE_COUNT; return err; } @@ -930,8 +936,6 @@ sa1100_set_power(si, 0); - MOD_DEC_USE_COUNT; - return 0; } @@ -947,56 +951,48 @@ return io->head ? 0 : -ENOMEM; } -static struct device_driver sa1100ir_driver = { - .name = "sa1100ir", - .bus = &system_bus_type, - .suspend = sa1100_irda_suspend, - .resume = sa1100_irda_resume, -}; - -static struct sys_device sa1100ir_device = { - .name = "sa1100ir", - .id = 0, - .root = NULL, - .dev = { - .name = "Intel Corporation SA11x0 [IrDA]", - .bus_id = "0", - .driver = &sa1100ir_driver, - }, -}; - -static int sa1100_irda_net_init(struct net_device *dev) +static int sa1100_irda_probe(struct device *_dev) { - struct sa1100_irda *si = dev->priv; + struct platform_device *pdev = to_platform_device(_dev); + struct net_device *dev; + struct sa1100_irda *si; unsigned int baudrate_mask; - int err = -ENOMEM; + int err; - si = kmalloc(sizeof(struct sa1100_irda), GFP_KERNEL); - if (!si) - goto out; + err = request_mem_region(__PREG(Ser2UTCR0), 0x24, "IrDA") ? 0 : -EBUSY; + if (err) + goto err_mem_1; + err = request_mem_region(__PREG(Ser2HSCR0), 0x1c, "IrDA") ? 0 : -EBUSY; + if (err) + goto err_mem_2; + err = request_mem_region(__PREG(Ser2HSCR2), 0x04, "IrDA") ? 0 : -EBUSY; + if (err) + goto err_mem_3; - memset(si, 0, sizeof(*si)); + dev = alloc_irdadev(sizeof(struct sa1100_irda)); + if (!dev) + goto err_mem_4; - si->dev = &sa1100ir_device.dev; + si = dev->priv; + si->dev = &pdev->dev; /* * Initialise the HP-SIR buffers */ err = sa1100_irda_init_iobuf(&si->rx_buff, 14384); if (err) - goto out; + goto err_mem_5; err = sa1100_irda_init_iobuf(&si->tx_buff, 4000); if (err) - goto out_free_rx; + goto err_mem_5; - dev->priv = si; dev->hard_start_xmit = sa1100_irda_hard_xmit; dev->open = sa1100_irda_start; dev->stop = sa1100_irda_stop; dev->do_ioctl = sa1100_irda_ioctl; dev->get_stats = sa1100_irda_stats; + dev->irq = IRQ_Ser2ICP; - irda_device_setup(dev); irda_init_max_qos_capabilies(&si->qos); /* @@ -1030,42 +1026,62 @@ Ser2UTCR4 = si->utcr4; Ser2HSCR0 = HSCR0_UART; - return 0; - - kfree(si->tx_buff.head); -out_free_rx: - kfree(si->rx_buff.head); -out: - kfree(si); + err = register_netdev(dev); + if (err == 0) + dev_set_drvdata(&pdev->dev, si); + if (err) { + err_mem_5: + kfree(si->tx_buff.head); + kfree(si->rx_buff.head); + free_netdev(dev); + err_mem_4: + release_mem_region(__PREG(Ser2HSCR2), 0x04); + err_mem_3: + release_mem_region(__PREG(Ser2HSCR0), 0x1c); + err_mem_2: + release_mem_region(__PREG(Ser2UTCR0), 0x24); + } + err_mem_1: return err; } -/* - * Remove all traces of this driver module from the kernel, so we can't be - * called. Note that the device has already been stopped, so we don't have - * to worry about interrupts or dma. - */ -static void sa1100_irda_net_uninit(struct net_device *dev) +static int sa1100_irda_remove(struct device *_dev) { - struct sa1100_irda *si = dev->priv; + struct net_device *dev = dev_get_drvdata(_dev); - dev->hard_start_xmit = NULL; - dev->open = NULL; - dev->stop = NULL; - dev->do_ioctl = NULL; - dev->get_stats = NULL; - dev->priv = NULL; - - kfree(si->tx_buff.head); - kfree(si->rx_buff.head); - kfree(si); + if (dev) { + struct sa1100_irda *si = dev->priv; + unregister_netdev(dev); + kfree(si->tx_buff.head); + kfree(si->rx_buff.head); + free_netdev(dev); + } + + release_mem_region(__PREG(Ser2HSCR2), 0x04); + release_mem_region(__PREG(Ser2HSCR0), 0x1c); + release_mem_region(__PREG(Ser2UTCR0), 0x24); + + return 0; } +static struct device_driver sa1100ir_driver = { + .name = "sa11x0-ir", + .bus = &platform_bus_type, + .probe = sa1100_irda_probe, + .remove = sa1100_irda_remove, + .suspend = sa1100_irda_suspend, + .resume = sa1100_irda_resume, +}; + +static struct platform_device sa1100ir_device = { + .name = "sa11x0-ir", + .id = 0, +}; + static int __init sa1100_irda_init(void) { - struct net_device *dev; - int err; + int ret; /* * Limit power level a sensible range. @@ -1075,103 +1091,30 @@ if (power_level > 3) power_level = 3; - err = request_mem_region(__PREG(Ser2UTCR0), 0x24, "IrDA") ? 0 : -EBUSY; - if (err) - goto err_mem_1; - err = request_mem_region(__PREG(Ser2HSCR0), 0x1c, "IrDA") ? 0 : -EBUSY; - if (err) - goto err_mem_2; - err = request_mem_region(__PREG(Ser2HSCR2), 0x04, "IrDA") ? 0 : -EBUSY; - if (err) - goto err_mem_3; - - driver_register(&sa1100ir_driver); - sys_device_register(&sa1100ir_device); - - rtnl_lock(); - dev = dev_alloc("irda%d", &err); - if (dev) { - dev->irq = IRQ_Ser2ICP; - dev->init = sa1100_irda_net_init; - dev->uninit = sa1100_irda_net_uninit; - - err = register_netdevice(dev); - - if (err) - kfree(dev); - else - dev_set_drvdata(&sa1100ir_device.dev, dev); + ret = driver_register(&sa1100ir_driver); + if (ret == 0) { + ret = platform_device_register(&sa1100ir_device); + if (ret) + driver_unregister(&sa1100ir_driver); } - rtnl_unlock(); - - if (err) { - sys_device_unregister(&sa1100ir_device); - driver_unregister(&sa1100ir_driver); - - release_mem_region(__PREG(Ser2HSCR2), 0x04); -err_mem_3: - release_mem_region(__PREG(Ser2HSCR0), 0x1c); -err_mem_2: - release_mem_region(__PREG(Ser2UTCR0), 0x24); - } -err_mem_1: - return err; + return ret; } static void __exit sa1100_irda_exit(void) { - struct net_device *dev = dev_get_drvdata(&sa1100ir_device.dev); - - if (dev) - unregister_netdev(dev); - - sys_device_unregister(&sa1100ir_device); driver_unregister(&sa1100ir_driver); - - release_mem_region(__PREG(Ser2HSCR2), 0x04); - release_mem_region(__PREG(Ser2HSCR0), 0x1c); - release_mem_region(__PREG(Ser2UTCR0), 0x24); - - if(dev) - free_netdev(dev); + platform_device_unregister(&sa1100ir_device); } -static int __init sa1100ir_setup(char *line) -{ - char *opt; - - if (!line) - return 0; - - while ((opt = strsep(&line, ",")) != NULL) { - if (!strncmp(opt, "max_rate:", 9)) { - max_rate = simple_strtoul(opt + 9, NULL, 0); - continue; - } - if (!strncmp(opt, "power_level:", 12)) { - power_level = simple_strtoul(opt + 12, NULL, 0); - continue; - } - if (!strncmp(opt, "tx_lpm:", 7)) { - tx_lpm = simple_strtoul(opt + 7, NULL, 0); - continue; - } - } - - return 1; -} - -__setup("sa1100ir=", sa1100ir_setup); - module_init(sa1100_irda_init); module_exit(sa1100_irda_exit); +module_param(power_level, int, 0); +module_param(tx_lpm, int, 0); +module_param(max_rate, int, 0); MODULE_AUTHOR("Russell King "); MODULE_DESCRIPTION("StrongARM SA1100 IrDA driver"); MODULE_LICENSE("GPL"); -MODULE_PARM(power_level, "i"); MODULE_PARM_DESC(power_level, "IrDA power level, 1 (low) to 3 (high)"); -MODULE_PARM(tx_lpm, "i"); MODULE_PARM_DESC(tx_lpm, "Enable transmitter low power (1.6us) mode"); -MODULE_PARM(max_rate, "i"); MODULE_PARM_DESC(max_rate, "Maximum baud rate (4000000, 115200, 57600, 38400, 19200, 9600)"); diff -Nru a/drivers/net/isa-skeleton.c b/drivers/net/isa-skeleton.c --- a/drivers/net/isa-skeleton.c Thu Jan 22 18:59:26 2004 +++ b/drivers/net/isa-skeleton.c Thu Jan 22 18:59:26 2004 @@ -104,8 +104,6 @@ /* Index to functions, as function prototypes. */ -extern int netcard_probe(struct net_device *dev); - static int netcard_probe1(struct net_device *dev, int ioaddr); static int net_open(struct net_device *dev); static int net_send_packet(struct sk_buff *skb, struct net_device *dev); @@ -129,11 +127,11 @@ * If dev->base_addr == 2, allocate space for the device and return success * (detachable devices only). */ -int __init -netcard_probe(struct net_device *dev) +static int __init do_netcard_probe(struct net_device *dev) { int i; int base_addr = dev->base_addr; + int irq = dev->irq; SET_MODULE_OWNER(dev); @@ -144,14 +142,49 @@ for (i = 0; netcard_portlist[i]; i++) { int ioaddr = netcard_portlist[i]; - if (check_region(ioaddr, NETCARD_IO_EXTENT)) - continue; if (netcard_probe1(dev, ioaddr) == 0) return 0; + dev->irq = irq; } return -ENODEV; } + +static void cleanup_card(struct net_device *dev) +{ +#ifdef jumpered_dma + free_dma(dev->dma); +#endif +#ifdef jumpered_interrupts + free_irq(dev->irq, dev); +#endif + release_region(dev->base_addr, NETCARD_IO_EXTENT); +} + +struct net_device * __init netcard_probe(int unit) +{ + struct net_device *dev = alloc_etherdev(sizeof(struct net_local)); + int err; + + if (!dev) + return ERR_PTR(-ENOMEM); + + sprintf(dev->name, "eth%d", unit); + netdev_boot_setup_check(dev); + + err = do_netcard_probe(dev); + if (err) + goto out; + err = register_netdev(dev); + if (err) + goto out1; + return dev; +out1: + cleanup_card(dev); +out: + free_netdev(dev); + return ERR_PTR(err); +} /* * This is the real probe routine. Linux has a history of friendly device @@ -163,6 +196,11 @@ struct net_local *np; static unsigned version_printed; int i; + int err = -ENODEV; + + /* Grab the region so that no one else tries to probe our ioports. */ + if (!request_region(ioaddr, NETCARD_IO_EXTENT, cardname)) + return -EBUSY; /* * For ethernet adaptors the first three octets of the station address @@ -171,9 +209,8 @@ */ if (inb(ioaddr + 0) != SA_ADDR0 || inb(ioaddr + 1) != SA_ADDR1 - || inb(ioaddr + 2) != SA_ADDR2) { - return -ENODEV; - } + || inb(ioaddr + 2) != SA_ADDR2) + goto out; if (net_debug && version_printed++ == 0) printk(KERN_DEBUG "%s", version); @@ -187,6 +224,7 @@ for (i = 0; i < 6; i++) printk(" %2.2x", dev->dev_addr[i] = inb(ioaddr + i)); + err = -EAGAIN; #ifdef jumpered_interrupts /* * If this board has jumpered interrupts, allocate the interrupt @@ -217,7 +255,7 @@ if (irqval) { printk("%s: unable to get IRQ %d (irqval=%d).\n", dev->name, dev->irq, irqval); - return -EAGAIN; + goto out; } } #endif /* jumpered interrupt */ @@ -229,7 +267,7 @@ if (dev->dma == 0) { if (request_dma(dev->dma, cardname)) { printk("DMA %d allocation failed.\n", dev->dma); - return -EAGAIN; + goto out1; } else printk(", assigned DMA %d.\n", dev->dma); } else { @@ -256,30 +294,18 @@ } if (i <= 0) { printk("DMA probe failed.\n"); - return -EAGAIN; + goto out1; } if (request_dma(dev->dma, cardname)) { printk("probed DMA %d allocation failed.\n", dev->dma); - return -EAGAIN; + goto out1; } } #endif /* jumpered DMA */ - /* Initialize the device structure. */ - if (dev->priv == NULL) { - dev->priv = kmalloc(sizeof(struct net_local), GFP_KERNEL); - if (dev->priv == NULL) - return -ENOMEM; - } - - memset(dev->priv, 0, sizeof(struct net_local)); - np = (struct net_local *)dev->priv; spin_lock_init(&np->lock); - /* Grab the region so that no one else tries to probe our ioports. */ - request_region(ioaddr, NETCARD_IO_EXTENT, cardname); - dev->open = net_open; dev->stop = net_close; dev->hard_start_xmit = net_send_packet; @@ -288,11 +314,14 @@ dev->tx_timeout = &net_tx_timeout; dev->watchdog_timeo = MY_TX_TIMEOUT; - - /* Fill in the fields of the device structure with ethernet values. */ - ether_setup(dev); - return 0; +out1: +#ifdef jumpered_interrupts + free_irq(dev->irq, dev); +#endif +out: + release_region(base_addr, NETCARD_IO_EXTENT); + return err; } static void net_tx_timeout(struct net_device *dev) @@ -635,7 +664,7 @@ #ifdef MODULE -static struct net_device this_device; +static struct net_device *this_device; static int io = 0x300; static int irq; static int dma; @@ -644,42 +673,38 @@ int init_module(void) { + struct net_device *dev; int result; if (io == 0) printk(KERN_WARNING "%s: You shouldn't use auto-probing with insmod!\n", cardname); + dev = alloc_etherdev(sizeof(struct net_local)); + if (!dev) + return -ENOMEM; /* Copy the parameters from insmod into the device structure. */ - this_device.base_addr = io; - this_device.irq = irq; - this_device.dma = dma; - this_device.mem_start = mem; - this_device.init = netcard_probe; - - if ((result = register_netdev(&this_device)) != 0) - return result; - - return 0; + dev->base_addr = io; + dev->irq = irq; + dev->dma = dma; + dev->mem_start = mem; + if (do_netcard_probe(dev) == 0) { + if (register_netdev(dev) == 0) + this_device = dev; + return 0; + } + cleanup_card(dev); + } + free_netdev(dev); + return -ENXIO; } void cleanup_module(void) { - unregister_netdev(&this_device); - /* - * If we don't do this, we can't re-insmod it later. - * Release irq/dma here, when you have jumpered versions and - * allocate them in net_probe1(). - */ - /* - free_irq(this_device.irq, dev); - free_dma(this_device.dma); - */ - release_region(this_device.base_addr, NETCARD_IO_EXTENT); - - if (this_device.priv) - kfree(this_device.priv); + unregister_netdev(this_device); + cleanup_card(this_device); + free_netdev(this_device); } #endif /* MODULE */ diff -Nru a/drivers/net/ixgb/ixgb_main.c b/drivers/net/ixgb/ixgb_main.c --- a/drivers/net/ixgb/ixgb_main.c Thu Jan 22 18:59:24 2004 +++ b/drivers/net/ixgb/ixgb_main.c Thu Jan 22 18:59:24 2004 @@ -446,7 +446,7 @@ iounmap(adapter->hw.hw_addr); err_ioremap: pci_release_regions(pdev); - kfree(netdev); + free_netdev(netdev); err_alloc_etherdev: return -ENOMEM; } diff -Nru a/drivers/net/jazzsonic.c b/drivers/net/jazzsonic.c --- a/drivers/net/jazzsonic.c Thu Jan 22 18:59:24 2004 +++ b/drivers/net/jazzsonic.c Thu Jan 22 18:59:24 2004 @@ -80,7 +80,6 @@ /* Index to functions, as function prototypes. */ -extern int sonic_probe(struct net_device *dev); static int sonic_probe1(struct net_device *dev, unsigned int base_addr, unsigned int irq); @@ -89,29 +88,57 @@ * Probe for a SONIC ethernet controller on a Mips Jazz board. * Actually probing is superfluous but we're paranoid. */ -int __init sonic_probe(struct net_device *dev) +struct net_device * __init sonic_probe(int unit) { - unsigned int base_addr = dev ? dev->base_addr : 0; + struct net_device *dev; + struct sonic_local *lp; + unsigned int base_addr; + int err = 0; int i; /* * Don't probe if we're not running on a Jazz board. */ if (mips_machgroup != MACH_GROUP_JAZZ) - return -ENODEV; - if (base_addr >= KSEG0) /* Check a single specified location. */ - return sonic_probe1(dev, base_addr, dev->irq); - else if (base_addr != 0) /* Don't probe at all. */ - return -ENXIO; - - for (i = 0; sonic_portlist[i].port; i++) { - int base_addr = sonic_portlist[i].port; - if (check_region(base_addr, 0x100)) - continue; - if (sonic_probe1(dev, base_addr, sonic_portlist[i].irq) == 0) - return 0; + return ERR_PTR(-ENODEV); + + dev = alloc_etherdev(0); + if (!dev) + return ERR_PTR(-ENOMEM); + + sprintf(dev->name, "eth%d", unit); + netdev_boot_setup_check(dev); + base_addr = dev->base_addr; + + if (base_addr >= KSEG0) { /* Check a single specified location. */ + err = sonic_probe1(dev, base_addr, dev->irq); + } else if (base_addr != 0) { /* Don't probe at all. */ + err = -ENXIO; + } else { + for (i = 0; sonic_portlist[i].port; i++) { + int io = sonic_portlist[i].port; + if (sonic_probe1(dev, io, sonic_portlist[i].irq) == 0) + break; + } + if (!sonic_portlist[i].port) + err = -ENODEV; } - return -ENODEV; + if (err) + goto out; + err = register_netdev(dev); + if (err) + goto out1; + return dev; +out1: + lp = dev->priv; + vdma_free(lp->rba_laddr); + kfree(lp->rba); + vdma_free(lp->cda_laddr); + kfree(lp); + release_region(dev->base_addr, 0x100); +out: + free_netdev(dev); + return ERR_PTR(err); } static int __init sonic_probe1(struct net_device *dev, unsigned int base_addr, @@ -121,8 +148,11 @@ unsigned int silicon_revision; unsigned int val; struct sonic_local *lp; + int err = -ENODEV; int i; + if (!request_region(base_addr, 0x100, dev->name)) + return -EBUSY; /* * get the Silicon Revision ID. If this is one of the known * one assume that we found a SONIC ethernet controller at @@ -140,12 +170,9 @@ if (known_revisions[i] == 0xffff) { printk("SONIC ethernet controller not found (0x%4x)\n", silicon_revision); - return -ENODEV; + goto out; } - if (!request_region(base_addr, 0x100, dev->name)) - return -EBUSY; - if (sonic_debug && version_printed++ == 0) printk(version); @@ -175,6 +202,8 @@ } printk(" IRQ %d\n", irq); + + err = -ENOMEM; /* Initialize the device structure. */ if (dev->priv == NULL) { @@ -196,7 +225,7 @@ if (lp == NULL) { printk("%s: couldn't allocate memory for descriptors\n", dev->name); - return -ENOMEM; + goto out; } memset(lp, 0, sizeof(struct sonic_local)); @@ -206,7 +235,7 @@ if (lp->cda_laddr == ~0UL) { printk("%s: couldn't get DMA page entry for " "descriptors\n", dev->name); - return -ENOMEM; + goto out1; } lp->tda_laddr = lp->cda_laddr + sizeof (lp->cda); @@ -219,7 +248,7 @@ if (!lp->rba) { printk("%s: couldn't allocate receive buffers\n", dev->name); - return -ENOMEM; + goto out2; } /* get virtual dma address */ @@ -228,7 +257,7 @@ if (lp->rba_laddr == ~0UL) { printk("%s: couldn't get DMA page entry for receive " "buffers\n",dev->name); - return -ENOMEM; + goto out3; } /* now convert pointer to KSEG1 pointer */ @@ -252,9 +281,16 @@ SONIC_WRITE(SONIC_FAET,0xffff); SONIC_WRITE(SONIC_MPT,0xffff); - /* Fill in the fields of the device structure with ethernet values. */ - ether_setup(dev); return 0; +out3: + kfree(lp->rba); +out2: + vdma_free(lp->cda_laddr); +out1: + kfree(lp); +out: + release_region(base_addr, 0x100); + return err; } /* diff -Nru a/drivers/net/lance.c b/drivers/net/lance.c --- a/drivers/net/lance.c Thu Jan 22 18:59:23 2004 +++ b/drivers/net/lance.c Thu Jan 22 18:59:23 2004 @@ -59,8 +59,8 @@ #include static unsigned int lance_portlist[] __initdata = { 0x300, 0x320, 0x340, 0x360, 0}; -int lance_probe(struct net_device *dev); static int lance_probe1(struct net_device *dev, int ioaddr, int irq, int options); +static int __init do_lance_probe(struct net_device *dev); #ifdef LANCE_DEBUG static int lance_debug = LANCE_DEBUG; @@ -274,7 +274,6 @@ static unsigned char lance_need_isa_bounce_buffers = 1; static int lance_open(struct net_device *dev); -static int lance_open_fail(struct net_device *dev); static void lance_init_ring(struct net_device *dev, int mode); static int lance_start_xmit(struct sk_buff *skb, struct net_device *dev); static int lance_rx(struct net_device *dev); @@ -286,10 +285,21 @@ +static void cleanup_card(struct net_device *dev) +{ + struct lance_private *lp = dev->priv; + if (dev->dma != 4) + free_dma(dev->dma); + release_region(dev->base_addr, LANCE_TOTAL_SIZE); + kfree(lp->tx_bounce_buffs); + kfree((void*)lp->rx_buffs); + kfree(lp); +} + #ifdef MODULE #define MAX_CARDS 8 /* Max number of interfaces (cards) per module */ -static struct net_device dev_lance[MAX_CARDS]; +static struct net_device *dev_lance[MAX_CARDS]; static int io[MAX_CARDS]; static int dma[MAX_CARDS]; static int irq[MAX_CARDS]; @@ -305,28 +315,35 @@ int init_module(void) { + struct net_device *dev; int this_dev, found = 0; for (this_dev = 0; this_dev < MAX_CARDS; this_dev++) { - struct net_device *dev = &dev_lance[this_dev]; - dev->irq = irq[this_dev]; - dev->base_addr = io[this_dev]; - dev->dma = dma[this_dev]; - dev->init = lance_probe; if (io[this_dev] == 0) { - if (this_dev != 0) break; /* only complain once */ + if (this_dev != 0) /* only complain once */ + break; printk(KERN_NOTICE "lance.c: Module autoprobing not allowed. Append \"io=0xNNN\" value(s).\n"); return -EPERM; } - if (register_netdev(dev) != 0) { - printk(KERN_WARNING "lance.c: No PCnet/LANCE card found (i/o = 0x%x).\n", io[this_dev]); - if (found != 0) return 0; /* Got at least one. */ - return -ENXIO; + dev = alloc_etherdev(0); + if (!dev) + break; + dev->irq = irq[this_dev]; + dev->base_addr = io[this_dev]; + dev->dma = dma[this_dev]; + if (do_lance_probe(dev) == 0) { + if (register_netdev(dev) == 0) { + dev_lance[found++] = dev; + continue; + } + cleanup_card(dev); } - found++; + free_netdev(dev); + break; } - - return 0; + if (found != 0) + return 0; + return -ENXIO; } void cleanup_module(void) @@ -334,13 +351,11 @@ int this_dev; for (this_dev = 0; this_dev < MAX_CARDS; this_dev++) { - struct net_device *dev = &dev_lance[this_dev]; - if (dev->priv != NULL) { + struct net_device *dev = dev_lance[this_dev]; + if (dev) { unregister_netdev(dev); - free_dma(dev->dma); - release_region(dev->base_addr, LANCE_TOTAL_SIZE); - kfree(dev->priv); - dev->priv = NULL; + cleanup_card(dev); + free_netdev(dev); } } } @@ -352,7 +367,7 @@ board probes now that kmalloc() can allocate ISA DMA-able regions. This also allows the LANCE driver to be used as a module. */ -int __init lance_probe(struct net_device *dev) +static int __init do_lance_probe(struct net_device *dev) { int *port, result; @@ -387,6 +402,31 @@ return -ENODEV; } +struct net_device * __init lance_probe(int unit) +{ + struct net_device *dev = alloc_etherdev(0); + int err; + + if (!dev) + return ERR_PTR(-ENODEV); + + sprintf(dev->name, "eth%d", unit); + netdev_boot_setup_check(dev); + + err = do_lance_probe(dev); + if (err) + goto out; + err = register_netdev(dev); + if (err) + goto out1; + return dev; +out1: + cleanup_card(dev); +out: + free_netdev(dev); + return ERR_PTR(err); +} + static int __init lance_probe1(struct net_device *dev, int ioaddr, int irq, int options) { struct lance_private *lp; @@ -398,6 +438,7 @@ int hp_builtin = 0; /* HP on-board ethernet. */ static int did_version; /* Already printed version info. */ unsigned long flags; + int err = -ENOMEM; /* First we look for special cases. Check for HP's on-board ethernet by looking for 'HP' in the BIOS. @@ -432,7 +473,7 @@ outw(88, ioaddr+LANCE_ADDR); if (inw(ioaddr+LANCE_ADDR) != 88) { lance_version = 0; - } else { /* Good, it's a newer chip. */ + } else { /* Good, it's a newer chip. */ int chip_version = inw(ioaddr+LANCE_DATA); outw(89, ioaddr+LANCE_ADDR); chip_version |= inw(ioaddr+LANCE_DATA) << 16; @@ -447,13 +488,9 @@ } } - /* We can't use init_etherdev() to allocate dev->priv because it must + /* We can't allocate dev->priv from alloc_etherdev() because it must a ISA DMA-able region. */ - dev = init_etherdev(dev, 0); - if (!dev) - return -ENOMEM; SET_MODULE_OWNER(dev); - dev->open = lance_open_fail; chipname = chip_table[lance_version].name; printk("%s: %s at %#3x,", dev->name, chipname, ioaddr); @@ -465,8 +502,7 @@ dev->base_addr = ioaddr; /* Make certain the data structures used by the LANCE are aligned and DMAble. */ - lp = (struct lance_private *)(((unsigned long)kmalloc(sizeof(*lp)+7, - GFP_DMA | GFP_KERNEL)+7) & ~7); + lp = kmalloc(sizeof(*lp), GFP_DMA | GFP_KERNEL); if(lp==NULL) return -ENODEV; if (lance_debug > 6) printk(" (#0x%05lx)", (unsigned long)lp); @@ -486,7 +522,7 @@ lp->tx_bounce_buffs = NULL; lp->chip_version = lance_version; - lp->devlock = SPIN_LOCK_UNLOCKED; + spin_lock_init(&lp->devlock); lp->init_block.mode = 0x0003; /* Disable Rx and Tx. */ for (i = 0; i < 6; i++) @@ -540,6 +576,7 @@ dma_channels = ((inb(DMA1_STAT_REG) >> 4) & 0x0f) | (inb(DMA2_STAT_REG) & 0xf0); } + err = -ENODEV; if (dev->irq >= 2) printk(" assigned IRQ %d", dev->irq); else if (lance_version != 0) { /* 7990 boards need DMA detection first. */ @@ -559,7 +596,7 @@ printk(", probed IRQ %d", dev->irq); else { printk(", failed to detect IRQ line.\n"); - return -ENODEV; + goto out_tx; } /* Check for the initialization done bit, 0x0100, which means @@ -573,7 +610,7 @@ } else if (dev->dma) { if (request_dma(dev->dma, chipname)) { printk("DMA %d allocation failed.\n", dev->dma); - return -ENODEV; + goto out_tx; } else printk(", assigned DMA %d.\n", dev->dma); } else { /* OK, we have to auto-DMA. */ @@ -613,7 +650,7 @@ } if (i == 4) { /* Failure: bail. */ printk("DMA detection failed.\n"); - return -ENODEV; + goto out_tx; } } @@ -629,7 +666,7 @@ dev->irq = probe_irq_off(irq_mask); if (dev->irq == 0) { printk(" Failed to detect the 7990 IRQ line.\n"); - return -ENODEV; + goto out_dma; } printk(" Auto-IRQ detected IRQ%d.\n", dev->irq); } @@ -655,17 +692,17 @@ dev->watchdog_timeo = TX_TIMEOUT; return 0; -out_rx: kfree((void*)lp->rx_buffs); -out_lp: kfree(lp); - return -ENOMEM; +out_dma: + if (dev->dma != 4) + free_dma(dev->dma); +out_tx: + kfree(lp->tx_bounce_buffs); +out_rx: + kfree((void*)lp->rx_buffs); +out_lp: + kfree(lp); + return err; } - -static int -lance_open_fail(struct net_device *dev) -{ - return -ENODEV; -} - static int diff -Nru a/drivers/net/lasi_82596.c b/drivers/net/lasi_82596.c --- a/drivers/net/lasi_82596.c Thu Jan 22 18:59:23 2004 +++ b/drivers/net/lasi_82596.c Thu Jan 22 18:59:23 2004 @@ -1149,12 +1149,11 @@ #define LAN_PROM_ADDR 0xF0810000 -static int __devinit i82596_probe(struct net_device *dev) +static int __devinit i82596_probe(struct net_device *dev, + struct device *gen_dev) { int i; struct i596_private *lp; - /* we're going to overwrite dev->priv, so pull the device out */ - struct device *gen_dev = dev->priv; char eth_addr[6]; dma_addr_t dma_addr; @@ -1204,7 +1203,6 @@ return -ENOMEM; } - ether_setup(dev); DEB(DEB_PROBE,printk("%s: 82596 at %#3lx,", dev->name, dev->base_addr)); for (i = 0; i < 6; i++) @@ -1537,12 +1535,19 @@ netdevice->base_addr = dev->hpa; netdevice->irq = dev->irq; - netdevice->init = i82596_probe; - netdevice->priv = &dev->dev; + + retval = i82596_probe(netdevice, &dev->dev); + if (retval) { + free_netdev(netdevice); + return -ENODEV; + } retval = register_netdev(netdevice); if (retval) { + struct i596_private *lp = netdevice->priv; printk(KERN_WARNING __FILE__ ": register_netdevice ret'd %d\n", retval); + dma_free_noncoherent(lp->dev, sizeof(struct i596_private), + (void *)netdevice->mem_start, lp->dma_addr); free_netdev(netdevice); return -ENODEV; }; diff -Nru a/drivers/net/lne390.c b/drivers/net/lne390.c --- a/drivers/net/lne390.c Thu Jan 22 18:59:26 2004 +++ b/drivers/net/lne390.c Thu Jan 22 18:59:26 2004 @@ -49,7 +49,6 @@ #include "8390.h" -int lne390_probe(struct net_device *dev); static int lne390_probe1(struct net_device *dev, int ioaddr); static int lne390_open(struct net_device *dev); @@ -103,9 +102,11 @@ * PROM for a match against the value assigned to Mylex. */ -int __init lne390_probe(struct net_device *dev) +static int __init do_lne390_probe(struct net_device *dev) { unsigned short ioaddr = dev->base_addr; + int irq = dev->irq; + int mem_start = dev->mem_start; int ret; SET_MODULE_OWNER(dev); @@ -135,11 +136,46 @@ if (lne390_probe1(dev, ioaddr) == 0) return 0; release_region(ioaddr, LNE390_IO_EXTENT); + dev->irq = irq; + dev->mem_start = mem_start; } return -ENODEV; } +static void cleanup_card(struct net_device *dev) +{ + free_irq(dev->irq, dev); + release_region(dev->base_addr, LNE390_IO_EXTENT); + if (ei_status.reg0) + iounmap((void *)dev->mem_start); +} + +struct net_device * __init lne390_probe(int unit) +{ + struct net_device *dev = alloc_ei_netdev(); + int err; + + if (!dev) + return ERR_PTR(-ENOMEM); + + sprintf(dev->name, "eth%d", unit); + netdev_boot_setup_check(dev); + + err = do_lne390_probe(dev); + if (err) + goto out; + err = register_netdev(dev); + if (err) + goto out1; + return dev; +out1: + cleanup_card(dev); +out: + free_netdev(dev); + return ERR_PTR(err); +} + static int __init lne390_probe1(struct net_device *dev, int ioaddr) { int i, revision, ret; @@ -174,11 +210,6 @@ return -ENODEV; } #endif - /* Allocate dev->priv and fill in 8390 specific dev fields. */ - if (ethdev_init(dev)) { - printk ("lne390.c: unable to allocate memory for dev->priv!\n"); - return -ENOMEM; - } printk("lne390.c: LNE390%X in EISA slot %d, address", 0xa+revision, ioaddr/0x1000); for(i = 0; i < ETHER_ADDR_LEN; i++) @@ -199,8 +230,6 @@ if ((ret = request_irq(dev->irq, ei_interrupt, 0, dev->name, dev))) { printk (" unable to get IRQ %d.\n", dev->irq); - kfree(dev->priv); - dev->priv = NULL; return ret; } @@ -270,12 +299,13 @@ dev->open = &lne390_open; dev->stop = &lne390_close; +#ifdef CONFIG_NET_POLL_CONTROLLER + dev->poll_controller = ei_poll; +#endif NS8390_init(dev, 0); return 0; cleanup: free_irq(dev->irq, dev); - kfree(dev->priv); - dev->priv = NULL; return ret; } @@ -373,7 +403,7 @@ #ifdef MODULE #define MAX_LNE_CARDS 4 /* Max number of LNE390 cards per module */ -static struct net_device dev_lne[MAX_LNE_CARDS]; +static struct net_device *dev_lne[MAX_LNE_CARDS]; static int io[MAX_LNE_CARDS]; static int irq[MAX_LNE_CARDS]; static int mem[MAX_LNE_CARDS]; @@ -389,26 +419,32 @@ int init_module(void) { + struct net_device *dev; int this_dev, found = 0; for (this_dev = 0; this_dev < MAX_LNE_CARDS; this_dev++) { - struct net_device *dev = &dev_lne[this_dev]; + if (io[this_dev] == 0 && this_dev != 0) + break; + dev = alloc_ei_netdev(); + if (!dev) + break; dev->irq = irq[this_dev]; dev->base_addr = io[this_dev]; dev->mem_start = mem[this_dev]; - dev->init = lne390_probe; - /* Default is to only install one card. */ - if (io[this_dev] == 0 && this_dev != 0) break; - if (register_netdev(dev) != 0) { - printk(KERN_WARNING "lne390.c: No LNE390 card found (i/o = 0x%x).\n", io[this_dev]); - if (found != 0) { /* Got at least one. */ - return 0; + if (do_lne390_probe(dev) == 0) { + if (register_netdev(dev) == 0) { + dev_lne[found++] = dev; + continue; } - return -ENXIO; + cleanup_card(dev); } - found++; - } - return 0; + free_netdev(dev); + printk(KERN_WARNING "lne390.c: No LNE390 card found (i/o = 0x%x).\n", io[this_dev]); + break; + } + if (found) + return 0; + return -ENXIO; } void cleanup_module(void) @@ -416,15 +452,11 @@ int this_dev; for (this_dev = 0; this_dev < MAX_LNE_CARDS; this_dev++) { - struct net_device *dev = &dev_lne[this_dev]; - if (dev->priv != NULL) { - void *priv = dev->priv; - free_irq(dev->irq, dev); - release_region(dev->base_addr, LNE390_IO_EXTENT); - if (ei_status.reg0) - iounmap((void *)dev->mem_start); + struct net_device *dev = dev_lne[this_dev]; + if (dev) { unregister_netdev(dev); - kfree(priv); + cleanup_card(dev); + free_netdev(dev); } } } diff -Nru a/drivers/net/lp486e.c b/drivers/net/lp486e.c --- a/drivers/net/lp486e.c Thu Jan 22 18:59:24 2004 +++ b/drivers/net/lp486e.c Thu Jan 22 18:59:24 2004 @@ -1314,18 +1314,23 @@ static int irq = IRQ; static int __init lp486e_init_module(void) { - struct net_device *dev; - - dev = alloc_etherdev(sizeof(struct i596_private)); + int err; + struct net_device *dev = alloc_etherdev(sizeof(struct i596_private)); if (!dev) return -ENOMEM; dev->irq = irq; dev->base_addr = io; - dev->init = lp486e_probe; - if (register_netdev(dev) != 0) { + err = lp486e_probe(dev); + if (err) { + free_netdev(dev); + return err; + } + err = register_netdev(dev); + if (err) { + release_region(dev->base_addr, LP486E_TOTAL_SIZE); free_netdev(dev); - return -EIO; + return err; } dev_lp486e = dev; full_duplex = 0; diff -Nru a/drivers/net/mac8390.c b/drivers/net/mac8390.c --- a/drivers/net/mac8390.c Thu Jan 22 18:59:25 2004 +++ b/drivers/net/mac8390.c Thu Jan 22 18:59:25 2004 @@ -124,11 +124,10 @@ static char version[] __initdata = "mac8390.c: v0.4 2001-05-15 David Huggins-Daines and others\n"; -extern int mac8390_probe(struct net_device * dev); extern enum mac8390_type mac8390_ident(struct nubus_dev * dev); extern int mac8390_memsize(unsigned long membase); extern int mac8390_memtest(struct net_device * dev); -extern int mac8390_initdev(struct net_device * dev, struct nubus_dev * ndev, +static int mac8390_initdev(struct net_device * dev, struct nubus_dev * ndev, enum mac8390_type type); static int mac8390_open(struct net_device * dev); @@ -223,43 +222,43 @@ return i * 0x1000; } -static int probed __initdata = 0; - -int __init mac8390_probe(struct net_device * dev) +struct net_device * __init mac8390_probe(int unit) { + struct net_device *dev; volatile unsigned short *i; - int boards_found = 0; int version_disp = 0; struct nubus_dev * ndev = NULL; + int err = -ENODEV; struct nubus_dir dir; struct nubus_dirent ent; int offset; + static unsigned int slots; enum mac8390_type cardtype; - if (probed) - return -ENODEV; - probed++; - /* probably should check for Nubus instead */ if (!MACH_IS_MAC) - return -ENODEV; + return ERR_PTR(-ENODEV); + + dev = alloc_ei_netdev(); + if (!dev) + return ERR_PTR(-ENOMEM); + + if (unit >= 0) + sprintf(dev->name, "eth%d", unit); + + SET_MODULE_OWNER(dev); while ((ndev = nubus_find_type(NUBUS_CAT_NETWORK, NUBUS_TYPE_ETHERNET, ndev))) { - - dev = NULL; - - if ((cardtype = mac8390_ident(ndev)) == MAC8390_NONE) + /* Have we seen it already? */ + if (slots & (1<board->slot)) continue; + slots |= 1<board->slot; - dev = init_etherdev(dev, 0); - if (dev == NULL) { - printk(KERN_ERR "Unable to allocate etherdev" - "structure!\n"); - return -ENOMEM; - } + if ((cardtype = mac8390_ident(ndev)) == MAC8390_NONE) + continue; if (version_disp == 0) { version_disp = 1; @@ -358,21 +357,25 @@ printk(KERN_ERR "Card type %s is" " unsupported, sorry\n", cardname[cardtype]); - return -ENODEV; + continue; } } /* Do the nasty 8390 stuff */ - if (mac8390_initdev(dev, ndev, cardtype)) - continue; - boards_found++; + if (!mac8390_initdev(dev, ndev, cardtype)) + break; } - /* We're outta here */ - if (boards_found > 0) - return 0; - else - return -ENODEV; + if (!ndev) + goto out; + err = register_netdev(dev); + if (err) + goto out; + return dev; + +out: + free_netdev(dev); + return ERR_PTR(err); } #ifdef MODULE @@ -380,26 +383,39 @@ MODULE_DESCRIPTION("Macintosh NS8390-based Nubus Ethernet driver"); MODULE_LICENSE("GPL"); +/* overkill, of course */ +static struct net_device *dev_mac8390[15]; int init_module(void) { - if (mac8390_probe(NULL)) { + int i; + for (i = 0; i < 15; i++) { + struct net_device *dev = mac8390_probe(-1); + if (IS_ERR(dev)) + break; + dev_mac890[i] = dev; + } + if (!i) { printk(KERN_NOTICE "mac8390.c: No useable cards found, driver NOT installed.\n"); return -ENODEV; } - lock_8390_module(); return 0; } void cleanup_module(void) { - /* FIXME: should probably keep track of net_device structs - somewhere and unregister them here? */ - unlock_8390_module(); + int i; + for (i = 0; i < 15; i++) { + struct net_device *dev = dev_mac890[i]; + if (dev) { + unregister_netdev(dev); + free_netdev(dev); + } + } } #endif /* MODULE */ -int __init mac8390_initdev(struct net_device * dev, struct nubus_dev * ndev, +static int __init mac8390_initdev(struct net_device * dev, struct nubus_dev * ndev, enum mac8390_type type) { static u32 fwrd4_offsets[16]={ @@ -423,15 +439,12 @@ int access_bitmode; - /* 8390 specific init for dev - allocates dev->priv */ - if (ethdev_init(dev)) { - printk(KERN_ERR "%s: Unable to allocate memory for dev->priv!\n", dev->name); - return -ENOMEM; - } - /* Now fill in our stuff */ dev->open = &mac8390_open; dev->stop = &mac8390_close; +#ifdef CONFIG_NET_POLL_CONTROLLER + dev->poll_controller = ei_poll; +#endif /* GAR, ei_status is actually a macro even though it looks global */ ei_status.name = cardname[type]; @@ -529,7 +542,6 @@ printk ("%s: unable to get IRQ %d.\n", dev->name, dev->irq); return -EAGAIN; } - MOD_INC_USE_COUNT; return 0; } @@ -537,7 +549,6 @@ { free_irq(dev->irq, dev); ei_close(dev); - MOD_DEC_USE_COUNT; return 0; } diff -Nru a/drivers/net/mac89x0.c b/drivers/net/mac89x0.c --- a/drivers/net/mac89x0.c Thu Jan 22 18:59:25 2004 +++ b/drivers/net/mac89x0.c Thu Jan 22 18:59:25 2004 @@ -123,7 +123,6 @@ /* Index to functions, as function prototypes. */ -extern int mac89x0_probe(struct net_device *dev); #if 0 extern void reset_chip(struct net_device *dev); #endif @@ -170,8 +169,9 @@ /* Probe for the CS8900 card in slot E. We won't bother looking anywhere else until we have a really good reason to do so. */ -int __init mac89x0_probe(struct net_device *dev) +struct net_device * __init mac89x0_probe(int unit) { + struct net_device *dev; static int once_is_enough; struct net_local *lp; static unsigned version_printed; @@ -179,18 +179,28 @@ unsigned rev_type = 0; unsigned long ioaddr; unsigned short sig; + int err = -ENODEV; + + dev = alloc_etherdev(sizeof(struct net_local)); + if (!dev) + return ERR_PTR(-ENOMEM); + + if (unit >= 0) { + sprintf(dev->name, "eth%d", unit); + netdev_boot_setup_check(dev); + } SET_MODULE_OWNER(dev); if (once_is_enough) - return -ENODEV; + goto out; once_is_enough = 1; /* We might have to parameterize this later */ slot = 0xE; /* Get out now if there's a real NuBus card in slot E */ if (nubus_find_slot(slot, NULL) != NULL) - return -ENODEV; + goto out; /* The pseudo-ISA bits always live at offset 0x300 (gee, wonder why...) */ @@ -206,21 +216,15 @@ local_irq_restore(flags); if (!card_present) - return -ENODEV; + goto out; } nubus_writew(0, ioaddr + ADD_PORT); sig = nubus_readw(ioaddr + DATA_PORT); if (sig != swab16(CHIP_EISA_ID_SIG)) - return -ENODEV; + goto out; /* Initialize the net_device structure. */ - if (dev->priv == NULL) { - dev->priv = kmalloc(sizeof(struct net_local), GFP_KERNEL); - if (!dev->priv) - return -ENOMEM; - memset(dev->priv, 0, sizeof(struct net_local)); - } lp = (struct net_local *)dev->priv; /* Fill in the 'dev' fields. */ @@ -258,9 +262,7 @@ /* Try to read the MAC address */ if ((readreg(dev, PP_SelfST) & (EEPROM_PRESENT | EEPROM_OK)) == 0) { printk("\nmac89x0: No EEPROM, giving up now.\n"); - kfree(dev->priv); - dev->priv = NULL; - return -ENODEV; + goto out1; } else { for (i = 0; i < ETH_ALEN; i += 2) { /* Big-endian (why??!) */ @@ -277,6 +279,7 @@ for (i = 0; i < ETH_ALEN; i++) printk("%2.2x%s", dev->dev_addr[i], ((i < ETH_ALEN-1) ? ":" : "")); + printk("\n"); dev->open = net_open; dev->stop = net_close; @@ -285,11 +288,15 @@ dev->set_multicast_list = &set_multicast_list; dev->set_mac_address = &set_mac_address; - /* Fill in the fields of the net_device structure with ethernet values. */ - ether_setup(dev); - - printk("\n"); + err = register_netdev(dev); + if (err) + goto out1; return 0; +out1: + nubus_writew(0, dev->base_addr + ADD_PORT); +out: + free_netdev(dev); + return ERR_PTR(err); } #if 0 @@ -619,7 +626,7 @@ #ifdef MODULE -static struct net_device dev_cs89x0; +static struct net_device *dev_cs89x0; static int debug; MODULE_PARM(debug, "i"); @@ -630,36 +637,20 @@ init_module(void) { net_debug = debug; - dev_cs89x0.init = mac89x0_probe; - dev_cs89x0.priv = kmalloc(sizeof(struct net_local), GFP_KERNEL); - if (!dev_cs89x0.priv) - return -ENOMEM; - memset(dev_cs89x0.priv, 0, sizeof(struct net_local)); - - if (register_netdev(&dev_cs89x0) != 0) { + dev_cs89x0 = mac89x0_probe(-1); + if (IS_ERR(dev_cs89x0)) { printk(KERN_WARNING "mac89x0.c: No card found\n"); - kfree(dev_cs89x0.priv); - return -ENXIO; - } + return PTR_ERR(dev_cs89x0); + } return 0; } void cleanup_module(void) { - -#endif -#ifdef MODULE - nubus_writew(0, dev_cs89x0.base_addr + ADD_PORT); -#endif -#ifdef MODULE - - if (dev_cs89x0.priv != NULL) { - /* Free up the private structure, or leak memory :-) */ - unregister_netdev(&dev_cs89x0); - kfree(dev_cs89x0.priv); - dev_cs89x0.priv = NULL; /* gets re-allocated by cs89x0_probe1 */ - } + unregister_netdev(dev_cs89x0); + nubus_writew(0, dev_cs89x0->base_addr + ADD_PORT); + free_netdev(dev_cs89x0); } #endif /* MODULE */ diff -Nru a/drivers/net/mace.c b/drivers/net/mace.c --- a/drivers/net/mace.c Thu Jan 22 18:59:24 2004 +++ b/drivers/net/mace.c Thu Jan 22 18:59:24 2004 @@ -142,6 +142,10 @@ } } + /* + * lazy allocation - it's a driver-wide thing and it will live until + * the unload, but we don't allocate it until it's needed + */ if (dummy_buf == NULL) { dummy_buf = kmalloc(RX_BUFLEN+2, GFP_KERNEL); if (dummy_buf == NULL) { @@ -150,7 +154,7 @@ } } - dev = init_etherdev(0, PRIV_BYTES); + dev = alloc_etherdev(PRIV_BYTES); if (!dev) return; SET_MODULE_OWNER(dev); @@ -160,16 +164,16 @@ if (!request_OF_resource(mace, 0, " (mace)")) { printk(KERN_ERR "MACE: can't request IO resource !\n"); - goto err_out; + goto out1; } if (!request_OF_resource(mace, 1, " (mace tx dma)")) { printk(KERN_ERR "MACE: can't request TX DMA resource !\n"); - goto err_out; + goto out2; } if (!request_OF_resource(mace, 2, " (mace tx dma)")) { printk(KERN_ERR "MACE: can't request RX DMA resource !\n"); - goto err_out; + goto out3; } dev->base_addr = mace->addrs[0].address; @@ -229,30 +233,42 @@ dev->set_multicast_list = mace_set_multicast; dev->set_mac_address = mace_set_address; - ether_setup(dev); - mace_reset(dev); - if (request_irq(dev->irq, mace_interrupt, 0, "MACE", dev)) + if (request_irq(dev->irq, mace_interrupt, 0, "MACE", dev)) { printk(KERN_ERR "MACE: can't get irq %d\n", dev->irq); + goto out4; + } if (request_irq(mace->intrs[1].line, mace_txdma_intr, 0, "MACE-txdma", - dev)) + dev)) { printk(KERN_ERR "MACE: can't get irq %d\n", mace->intrs[1].line); + goto out5; + } if (request_irq(mace->intrs[2].line, mace_rxdma_intr, 0, "MACE-rxdma", - dev)) + dev)) { printk(KERN_ERR "MACE: can't get irq %d\n", mace->intrs[2].line); + goto out6; + } + if (register_netdev(dev) != 0) + goto out7; mp->next_mace = mace_devs; mace_devs = dev; return; -err_out: - unregister_netdev(dev); - if (mp->of_node) { - release_OF_resource(mp->of_node, 0); - release_OF_resource(mp->of_node, 1); - release_OF_resource(mp->of_node, 2); - } +out7: + free_irq(mp->rx_dma_intr, dev); +out6: + free_irq(mp->tx_dma_intr, dev); +out5: + free_irq(dev->irq, dev); +out4: + release_OF_resource(mp->of_node, 2); +out3: + release_OF_resource(mp->of_node, 1); +out2: + release_OF_resource(mp->of_node, 0); +out1: free_netdev(dev); } @@ -975,7 +991,7 @@ release_OF_resource(mp->of_node, 1); release_OF_resource(mp->of_node, 2); - kfree(dev); + free_netdev(dev); } if (dummy_buf != NULL) { kfree(dummy_buf); diff -Nru a/drivers/net/macmace.c b/drivers/net/macmace.c --- a/drivers/net/macmace.c Thu Jan 22 18:59:24 2004 +++ b/drivers/net/macmace.c Thu Jan 22 18:59:24 2004 @@ -180,7 +180,7 @@ * model of Macintrash has a MACE (AV macintoshes) */ -int mace_probe(struct net_device *unused) +struct net_device *mace_probe(int unit) { int j; struct mace_data *mp; @@ -188,13 +188,19 @@ struct net_device *dev; unsigned char checksum = 0; static int found = 0; + int err; - if (found || macintosh_config->ether_type != MAC_ETHER_MACE) return -ENODEV; + if (found || macintosh_config->ether_type != MAC_ETHER_MACE) + return ERR_PTR(-ENODEV); found = 1; /* prevent 'finding' one on every device probe */ - dev = init_etherdev(0, PRIV_BYTES); - if (!dev) return -ENOMEM; + dev = alloc_etherdev(PRIV_BYTES); + if (!dev) + return ERR_PTR(-ENOMEM); + + if (unit >= 0) + sprintf(dev->name, "eth%d", unit); mp = (struct mace_data *) dev->priv; dev->base_addr = (u32)MACE_BASE; @@ -221,7 +227,10 @@ checksum ^= bitrev(addr[j<<4]); } - if (checksum != 0xFF) return -ENODEV; + if (checksum != 0xFF) { + free_netdev(dev); + return ERR_PTR(-ENODEV); + } memset(&mp->stats, 0, sizeof(mp->stats)); @@ -234,13 +243,16 @@ dev->set_multicast_list = mace_set_multicast; dev->set_mac_address = mace_set_address; - ether_setup(dev); - printk(KERN_INFO "%s: 68K MACE, hardware address %.2X", dev->name, dev->dev_addr[0]); for (j = 1 ; j < 6 ; j++) printk(":%.2X", dev->dev_addr[j]); printk("\n"); - return 0; + err = register_netdev(dev); + if (!err) + return dev; + + free_netdev(dev); + return ERR_PTR(err); } /* diff -Nru a/drivers/net/macsonic.c b/drivers/net/macsonic.c --- a/drivers/net/macsonic.c Thu Jan 22 18:59:23 2004 +++ b/drivers/net/macsonic.c Thu Jan 22 18:59:23 2004 @@ -74,7 +74,6 @@ static int reg_offset; -extern int macsonic_probe(struct net_device* dev); extern int mac_onboard_sonic_probe(struct net_device* dev); extern int mac_nubus_sonic_probe(struct net_device* dev); @@ -110,14 +109,38 @@ #define SONIC_READ_PROM(addr) nubus_readb(prom_addr+addr) -int __init macsonic_probe(struct net_device* dev) +struct net_device * __init macsonic_probe(int unit) { - int rv; + struct net_device *dev = alloc_etherdev(0); + int err; + + if (!dev) + return ERR_PTR(-ENOMEM); + + if (unit >= 0) + sprintf(dev->name, "eth%d", unit); + + SET_MODULE_OWNER(dev); /* This will catch fatal stuff like -ENOMEM as well as success */ - if ((rv = mac_onboard_sonic_probe(dev)) != -ENODEV) - return rv; - return mac_nubus_sonic_probe(dev); + err = mac_onboard_sonic_probe(dev); + if (err == 0) + goto found; + if (err != -ENODEV) + goto out; + err = mac_nubus_sonic_probe(dev); + if (err) + goto out; +found: + err = register_netdev(dev); + if (err) + goto out1; + return dev; +out1: + kfree(dev->priv); +out: + free_netdev(dev); + return ERR_PTR(err); } /* @@ -195,6 +218,7 @@ if ((lp->rba = (char *) kmalloc(SONIC_NUM_RRS * SONIC_RBSIZE, GFP_KERNEL | GFP_DMA)) == NULL) { printk(KERN_ERR "%s: couldn't allocate receive buffers\n", dev->name); + dev->priv = NULL; kfree(lp); return -ENOMEM; } @@ -229,8 +253,6 @@ sonic_write(dev, SONIC_FAET, 0xffff); sonic_write(dev, SONIC_MPT, 0xffff); - /* Fill in the fields of the device structure with ethernet values. */ - ether_setup(dev); return 0; } @@ -344,30 +366,6 @@ printk("yes\n"); - if (dev) { - dev = init_etherdev(dev, sizeof(struct sonic_local)); - if (!dev) - return -ENOMEM; - /* methinks this will always be true but better safe than sorry */ - if (dev->priv == NULL) { - dev->priv = kmalloc(sizeof(struct sonic_local), GFP_KERNEL); - if (!dev->priv) - return -ENOMEM; - } - } else { - dev = init_etherdev(NULL, sizeof(struct sonic_local)); - } - - if (dev == NULL) - return -ENOMEM; - - if(dev->priv) { - printk("%s: warning! sonic entering with priv already allocated!\n", - dev->name); - printk("%s: discarding, will attempt to reallocate\n", dev->name); - dev->priv = NULL; - } - /* Danger! My arms are flailing wildly! You *must* set this before using sonic_read() */ @@ -497,7 +495,6 @@ { static int slots; struct nubus_dev* ndev = NULL; - struct sonic_local* lp; unsigned long base_addr, prom_addr; u16 sonic_dcr; int id; @@ -567,25 +564,6 @@ return -ENODEV; } - if (dev) { - dev = init_etherdev(dev, sizeof(struct sonic_local)); - if (!dev) - return -ENOMEM; - /* methinks this will always be true but better safe than sorry */ - if (dev->priv == NULL) { - dev->priv = kmalloc(sizeof(struct sonic_local), GFP_KERNEL); - if (!dev->priv) /* FIXME: kfree dev if necessary */ - return -ENOMEM; - } - } else { - dev = init_etherdev(NULL, sizeof(struct sonic_local)); - } - - if (dev == NULL) - return -ENOMEM; - - lp = (struct sonic_local*) dev->priv; - memset(lp, 0, sizeof(struct sonic_local)); /* Danger! My arms are flailing wildly! You *must* set this before using sonic_read() */ dev->base_addr = base_addr; @@ -631,8 +609,7 @@ } #ifdef MODULE -static char namespace[16] = ""; -static struct net_device dev_macsonic; +static struct net_device *dev_macsonic; MODULE_PARM(sonic_debug, "i"); MODULE_PARM_DESC(sonic_debug, "macsonic debug level (1-4)"); @@ -641,24 +618,20 @@ int init_module(void) { - dev_macsonic.name = namespace; - dev_macsonic.init = macsonic_probe; - - if (register_netdev(&dev_macsonic) != 0) { + dev_macsonic = macsonic_probe(-1); + if (IS_ERR(dev_macsonic)) { printk(KERN_WARNING "macsonic.c: No card found\n"); - return -ENXIO; - } + return PTR_ERR(dev_macsonic); + } return 0; } void cleanup_module(void) { - if (dev_macsonic.priv != NULL) { - unregister_netdev(&dev_macsonic); - kfree(dev_macsonic.priv); - dev_macsonic.priv = NULL; - } + unregister_netdev(dev_macsonic); + kfree(dev_macsonic->priv); + free_netdev(dev_macsonic); } #endif /* MODULE */ diff -Nru a/drivers/net/meth.c b/drivers/net/meth.c --- a/drivers/net/meth.c Thu Jan 22 18:59:26 2004 +++ b/drivers/net/meth.c Thu Jan 22 18:59:26 2004 @@ -95,7 +95,6 @@ spinlock_t meth_lock; } meth_private; -extern struct net_device meth_devs[]; void meth_tx_timeout (struct net_device *dev); void meth_interrupt(int irq, void *dev_id, struct pt_regs *pregs); @@ -762,17 +761,16 @@ /* * The init function (sometimes called probe). - * It is invoked by register_netdev() */ -int meth_init(struct net_device *dev) +static struct net_device *meth_init(struct net_device *dev) { + struct net_device *dev; meth_private *priv; int ret; - /* - * Then, assign other fields in dev, using ether_setup() and some - * hand assignments - */ - ether_setup(dev); /* assign some of the fields */ + + dev = alloc_etherdev(sizeof(struct meth_private)); + if (!dev) + return ERR_PTR(-ENOMEM); dev->open = meth_open; dev->stop = meth_release; @@ -787,16 +785,8 @@ dev->irq = MACE_ETHERNET_IRQ; SET_MODULE_OWNER(dev); - /* - * Then, allocate the priv field. This encloses the statistics - * and a few private fields. - */ - priv = kmalloc(sizeof(struct meth_private), GFP_KERNEL); - if (priv == NULL) - return -ENOMEM; - dev->priv=priv; - memset(priv, 0, sizeof(struct meth_private)); - spin_lock_init(&((struct meth_private *) dev->priv)->meth_lock); + priv = dev->priv; + spin_lock_init(&priv->meth_lock); /* * Make the usual checks: check_region(), probe irq, ... -ENODEV * should be returned if no device found. No resource should be @@ -807,28 +797,41 @@ priv->phy_addr = -1; /* No phy is known yet... */ /* Initialize the hardware */ - if((ret=meth_reset(dev)) < 0) - return ret; + ret = meth_reset(dev); + if (ret < 0) + goto out; /* Allocate the ring buffers */ - if((ret=meth_init_tx_ring(priv))<0||(ret=meth_init_rx_ring(priv))<0){ - meth_free_tx_ring(priv); - meth_free_rx_ring(priv); - return ret; - } + ret = meth_init_tx_ring(priv); + if (ret < 0) + goto out; + + ret = meth_init_rx_ring(priv); + if (ret < 0) + goto out1; + + ret = register_netdev(dev); + if (ret) + goto out2; printk("SGI O2 Fast Ethernet rev. %ld\n", priv->regs->mac_ctrl >> 29); - return 0; + return ret; + +out2: + meth_free_rx_ring(priv); +out1: + meth_free_tx_ring(priv); +out: + free_netdev(dev); + return ERR_PTR(ret); } /* * The devices */ -struct net_device meth_devs[1] = { - { init: meth_init, } /* init, nothing more */ -}; +struct net_device *meth_dev; /* * Finally, the module stuff @@ -836,23 +839,19 @@ int meth_init_module(void) { - int result, device_present = 0; - - strcpy(meth_devs[0].name, "eth%d"); - - if ( (result = register_netdev(meth_devs)) ) - printk("meth: error %i registering device \"%s\"\n", - result, meth_devs->name); - else device_present++; - - return device_present ? 0 : -ENODEV; + meth_dev = meth_init(); + if (IS_ERR(meth_dev)) + return PTR_ERR(meth_dev); + return 0; } void meth_cleanup(void) { - kfree(meth_devs->priv); - unregister_netdev(meth_devs); - return; + meth_private *priv = meth_dev->priv; + unregister_netdev(meth_dev); + meth_free_rx_ring(priv); + meth_free_tx_ring(priv); + free_netdev(meth_dev); } module_init(meth_init_module); diff -Nru a/drivers/net/mvme147.c b/drivers/net/mvme147.c --- a/drivers/net/mvme147.c Thu Jan 22 18:59:24 2004 +++ b/drivers/net/mvme147.c Thu Jan 22 18:59:24 2004 @@ -41,7 +41,7 @@ struct m147lance_private { struct lance_private lance; void *base; - void *ram; + unsigned long ram; }; /* function prototypes... This is easy because all the grot is in the @@ -49,7 +49,6 @@ * plus board-specific init, open and close actions. * Oh, and we need to tell the generic code how to read and write LANCE registers... */ -int mvme147lance_probe(struct net_device *dev); static int m147lance_open(struct net_device *dev); static int m147lance_close(struct net_device *dev); static void m147lance_writerap(struct m147lance_private *lp, unsigned short value); @@ -60,29 +59,29 @@ typedef void (*writerdp_t)(void *, unsigned short); typedef unsigned short (*readrdp_t)(void *); -#ifdef MODULE -static struct m147lance_private *root_m147lance_dev; -#endif - /* Initialise the one and only on-board 7990 */ -int __init mvme147lance_probe(struct net_device *dev) +struct net_device * __init mvme147lance_probe(int unit) { + struct net_device *dev; static int called; static const char name[] = "MVME147 LANCE"; struct m147lance_private *lp; u_long *addr; u_long address; + int err; if (!MACH_IS_MVME147 || called) - return -ENODEV; + return ERR_PTR(-ENODEV); called++; - SET_MODULE_OWNER(dev); + dev = alloc_etherdev(sizeof(struct m147lance_private)); + if (!dev) + return ERR_PTR(-ENOMEM); - dev->priv = kmalloc(sizeof(struct m147lance_private), GFP_KERNEL); - if (dev->priv == NULL) - return -ENOMEM; - memset(dev->priv, 0, sizeof(struct m147lance_private)); + if (unit >= 0) + sprintf(dev->name, "eth%d", unit); + + SET_MODULE_OWNER(dev); /* Fill the dev fields */ dev->base_addr = (unsigned long)MVME147_LANCE_BASE; @@ -114,11 +113,12 @@ dev->dev_addr[5]); lp = (struct m147lance_private *)dev->priv; - lp->ram = (void *)__get_dma_pages(GFP_ATOMIC, 3); /* 16K */ + lp->ram = __get_dma_pages(GFP_ATOMIC, 3); /* 16K */ if (!lp->ram) { printk("%s: No memory for LANCE buffers\n", dev->name); - return -ENODEV; + free_netdev(dev); + return ERR_PTR(-ENOMEM); } lp->lance.name = (char*)name; /* discards const, shut up gcc */ @@ -134,15 +134,15 @@ lp->lance.lance_log_tx_bufs = LANCE_LOG_TX_BUFFERS; lp->lance.rx_ring_mod_mask = RX_RING_MOD_MASK; lp->lance.tx_ring_mod_mask = TX_RING_MOD_MASK; - ether_setup(dev); -#ifdef MODULE - dev->ifindex = dev_new_index(); - lp->next_module = root_m147lance_dev; - root_m147lance_dev = lp; -#endif /* MODULE */ + err = register_netdev(dev); + if (err) { + free_pages(lp->ram, 3); + free_netdev(dev); + return ERR_PTR(err); + } - return 0; + return dev; } static void m147lance_writerap(struct m147lance_private *lp, unsigned short value) @@ -185,23 +185,21 @@ #ifdef MODULE MODULE_LICENSE("GPL"); +static struct net_device *dev_mvme147_lance; int init_module(void) { - root_lance_dev = NULL; - return mvme147lance_probe(NULL); + dev_mvme147_lance = mvme147lance_probe(-1); + if (IS_ERR(dev_mvme147_lance)) + return PTR_ERR(dev_mvme147_lance); + return 0; } void cleanup_module(void) { - /* Walk the chain of devices, unregistering them */ - struct m147lance_private *lp; - while (root_m147lance_dev) { - lp = root_m147lance_dev->next_module; - unregister_netdev(root_lance_dev->dev); - free_pages(lp->ram, 3); - free_netdev(root_lance_dev->dev); - root_lance_dev = lp; - } + struct m147lance_private *lp = dev_mvme147_lance->priv; + unregister_netdev(dev_mvme147_lance); + free_pages(lp->ram, 3); + free_netdev(dev_mvme147_lance); } #endif /* MODULE */ diff -Nru a/drivers/net/ne.c b/drivers/net/ne.c --- a/drivers/net/ne.c Thu Jan 22 18:59:25 2004 +++ b/drivers/net/ne.c Thu Jan 22 18:59:25 2004 @@ -126,7 +126,6 @@ #define NESM_START_PG 0x40 /* First page of TX buffer */ #define NESM_STOP_PG 0x80 /* Last page +1 of RX ring */ -int ne_probe(struct net_device *dev); static int ne_probe1(struct net_device *dev, int ioaddr); static int ne_probe_isapnp(struct net_device *dev); @@ -163,9 +162,10 @@ E2010 starts at 0x100 and ends at 0x4000. E2010-x starts at 0x100 and ends at 0xffff. */ -int __init ne_probe(struct net_device *dev) +static int __init do_ne_probe(struct net_device *dev) { unsigned int base_addr = dev->base_addr; + int irq = dev->irq; SET_MODULE_OWNER(dev); @@ -183,6 +183,7 @@ /* Last resort. The semi-risky ISA auto-probe. */ for (base_addr = 0; netcard_portlist[base_addr] != 0; base_addr++) { int ioaddr = netcard_portlist[base_addr]; + dev->irq = irq; if (ne_probe1(dev, ioaddr) == 0) return 0; } @@ -191,6 +192,40 @@ return -ENODEV; } +static void cleanup_card(struct net_device *dev) +{ + struct pnp_dev *idev = (struct pnp_dev *)ei_status.priv; + if (idev) + pnp_device_detach(idev); + free_irq(dev->irq, dev); + release_region(dev->base_addr, NE_IO_EXTENT); +} + +struct net_device * __init ne_probe(int unit) +{ + struct net_device *dev = alloc_ei_netdev(); + int err; + + if (!dev) + return ERR_PTR(-ENOMEM); + + sprintf(dev->name, "eth%d", unit); + netdev_boot_setup_check(dev); + + err = do_ne_probe(dev); + if (err) + goto out; + err = register_netdev(dev); + if (err) + goto out1; + return dev; +out1: + cleanup_card(dev); +out: + free_netdev(dev); + return ERR_PTR(err); +} + static int __init ne_probe_isapnp(struct net_device *dev) { int i; @@ -425,20 +460,12 @@ goto err_out; } - /* Allocate dev->priv and fill in 8390 specific dev fields. */ - if (ethdev_init(dev)) - { - printk (" unable to get memory for dev->priv.\n"); - ret = -ENOMEM; - goto err_out; - } - /* Snarf the interrupt now. There's no point in waiting since we cannot share and the board will usually be enabled. */ ret = request_irq(dev->irq, ei_interrupt, 0, name, dev); if (ret) { printk (" unable to get IRQ %d (errno=%d).\n", dev->irq, ret); - goto err_out_kfree; + goto err_out; } dev->base_addr = ioaddr; @@ -469,12 +496,12 @@ ei_status.priv = 0; dev->open = &ne_open; dev->stop = &ne_close; +#ifdef CONFIG_NET_POLL_CONTROLLER + dev->poll_controller = ei_poll; +#endif NS8390_init(dev, 0); return 0; -err_out_kfree: - kfree(dev->priv); - dev->priv = NULL; err_out: release_region(ioaddr, NE_IO_EXTENT); return ret; @@ -734,7 +761,7 @@ #ifdef MODULE #define MAX_NE_CARDS 4 /* Max number of NE cards per module */ -static struct net_device dev_ne[MAX_NE_CARDS]; +static struct net_device *dev_ne[MAX_NE_CARDS]; static int io[MAX_NE_CARDS]; static int irq[MAX_NE_CARDS]; static int bad[MAX_NE_CARDS]; /* 0xbad = bad sig or no reset ack */ @@ -758,25 +785,31 @@ int this_dev, found = 0; for (this_dev = 0; this_dev < MAX_NE_CARDS; this_dev++) { - struct net_device *dev = &dev_ne[this_dev]; + struct net_device *dev = alloc_ei_netdev(); + if (!dev) + break; dev->irq = irq[this_dev]; dev->mem_end = bad[this_dev]; dev->base_addr = io[this_dev]; - dev->init = ne_probe; - if (register_netdev(dev) == 0) { - found++; - continue; - } - if (found != 0) { /* Got at least one. */ - return 0; + if (do_ne_probe(dev) == 0) { + if (register_netdev(dev) == 0) { + dev_ne[found++] = dev; + continue; + } + cleanup_card(dev); } + free_netdev(dev); + if (found) + break; if (io[this_dev] != 0) printk(KERN_WARNING "ne.c: No NE*000 card found at i/o = %#x\n", io[this_dev]); else printk(KERN_NOTICE "ne.c: You must supply \"io=0xNNN\" value(s) for ISA cards.\n"); return -ENXIO; } - return 0; + if (found) + return 0; + return -ENODEV; } void cleanup_module(void) @@ -784,16 +817,11 @@ int this_dev; for (this_dev = 0; this_dev < MAX_NE_CARDS; this_dev++) { - struct net_device *dev = &dev_ne[this_dev]; - if (dev->priv != NULL) { - void *priv = dev->priv; - struct pnp_dev *idev = (struct pnp_dev *)ei_status.priv; - if (idev) - pnp_device_detach(idev); - free_irq(dev->irq, dev); - release_region(dev->base_addr, NE_IO_EXTENT); + struct net_device *dev = dev_ne[this_dev]; + if (dev) { unregister_netdev(dev); - kfree(priv); + cleanup_card(dev); + free_netdev(dev); } } } diff -Nru a/drivers/net/ne2.c b/drivers/net/ne2.c --- a/drivers/net/ne2.c Thu Jan 22 18:59:27 2004 +++ b/drivers/net/ne2.c Thu Jan 22 18:59:27 2004 @@ -242,7 +242,7 @@ * Note that at boot, this probe only picks up one card at a time. */ -int __init ne2_probe(struct net_device *dev) +static int __init do_ne2_probe(struct net_device *dev) { static int current_mca_slot = -1; int i; @@ -262,16 +262,52 @@ mca_find_unused_adapter(ne2_adapters[i].id, 0); if((current_mca_slot != MCA_NOTFOUND) && !adapter_found) { + int res; mca_set_adapter_name(current_mca_slot, ne2_adapters[i].name); mca_mark_as_used(current_mca_slot); - return ne2_probe1(dev, current_mca_slot); + res = ne2_probe1(dev, current_mca_slot); + if (res) + mca_mark_as_unused(current_mca_slot); + return res; } } return -ENODEV; } +static void cleanup_card(struct net_device *dev) +{ + mca_mark_as_unused(ei_status.priv); + mca_set_adapter_procfn( ei_status.priv, NULL, NULL); + free_irq(dev->irq, dev); + release_region(dev->base_addr, NE_IO_EXTENT); +} + +struct net_device * __init ne2_probe(int unit) +{ + struct net_device *dev = alloc_ei_netdev(); + int err; + + if (!dev) + return ERR_PTR(-ENOMEM); + + sprintf(dev->name, "eth%d", unit); + netdev_boot_setup_check(dev); + + err = do_ne2_probe(dev); + if (err) + goto out; + err = register_netdev(dev); + if (err) + goto out1; + return dev; +out1: + cleanup_card(dev); +out: + free_netdev(dev); + return ERR_PTR(err); +} static int ne2_procinfo(char *buf, int slot, struct net_device *dev) { @@ -443,14 +479,6 @@ dev->base_addr = base_addr; - /* Allocate dev->priv and fill in 8390 specific dev fields. */ - if (ethdev_init(dev)) { - printk (" unable to get memory for dev->priv.\n"); - free_irq(dev->irq, dev); - retval = -ENOMEM; - goto out; - } - for(i = 0; i < ETHER_ADDR_LEN; i++) { printk(" %2.2x", SA_prom[i]); dev->dev_addr[i] = SA_prom[i]; @@ -481,6 +509,9 @@ dev->open = &ne_open; dev->stop = &ne_close; +#ifdef CONFIG_NET_POLL_CONTROLLER + dev->poll_controller = ei_poll; +#endif NS8390_init(dev, 0); return 0; out: @@ -735,7 +766,7 @@ #ifdef MODULE #define MAX_NE_CARDS 4 /* Max number of NE cards per module */ -static struct net_device dev_ne[MAX_NE_CARDS]; +static struct net_device *dev_ne[MAX_NE_CARDS]; static int io[MAX_NE_CARDS]; static int irq[MAX_NE_CARDS]; static int bad[MAX_NE_CARDS]; /* 0xbad = bad sig or no reset ack */ @@ -754,23 +785,30 @@ int init_module(void) { + struct net_device *dev; int this_dev, found = 0; for (this_dev = 0; this_dev < MAX_NE_CARDS; this_dev++) { - struct net_device *dev = &dev_ne[this_dev]; + dev = alloc_ei_netdev(); + if (!dev) + break; dev->irq = irq[this_dev]; dev->mem_end = bad[this_dev]; dev->base_addr = io[this_dev]; - dev->init = ne2_probe; - if (register_netdev(dev) != 0) { - if (found != 0) return 0; /* Got at least one. */ - - printk(KERN_WARNING "ne2.c: No NE/2 card found.\n"); - return -ENXIO; + if (do_ne2_probe(dev) == 0) { + if (register_netdev(dev) == 0) { + dev_ne[found++] = dev; + continue; + } + cleanup_card(dev); } - found++; + free_netdev(dev); + break; } - return 0; + if (found) + return 0; + printk(KERN_WARNING "ne2.c: No NE/2 card found\n"); + return -ENXIO; } void cleanup_module(void) @@ -778,14 +816,11 @@ int this_dev; for (this_dev = 0; this_dev < MAX_NE_CARDS; this_dev++) { - struct net_device *dev = &dev_ne[this_dev]; - if (dev->priv != NULL) { - mca_mark_as_unused(ei_status.priv); - mca_set_adapter_procfn( ei_status.priv, NULL, NULL); - kfree(dev->priv); - free_irq(dev->irq, dev); - release_region(dev->base_addr, NE_IO_EXTENT); + struct net_device *dev = dev_ne[this_dev]; + if (dev) { unregister_netdev(dev); + cleanup_card(dev); + free_netdev(dev); } } } diff -Nru a/drivers/net/ne2k-pci.c b/drivers/net/ne2k-pci.c --- a/drivers/net/ne2k-pci.c Thu Jan 22 18:59:24 2004 +++ b/drivers/net/ne2k-pci.c Thu Jan 22 18:59:24 2004 @@ -359,6 +359,9 @@ dev->open = &ne2k_pci_open; dev->stop = &ne2k_pci_close; dev->ethtool_ops = &ne2k_pci_ethtool_ops; +#ifdef CONFIG_NET_POLL_CONTROLLER + dev->poll_controller = ei_poll; +#endif NS8390_init(dev, 0); i = register_netdev(dev); diff -Nru a/drivers/net/ne2k_cbus.c b/drivers/net/ne2k_cbus.c --- a/drivers/net/ne2k_cbus.c Thu Jan 22 18:59:24 2004 +++ b/drivers/net/ne2k_cbus.c Thu Jan 22 18:59:24 2004 @@ -78,7 +78,6 @@ #include "ne2k_cbus.h" -int ne_probe(struct net_device *dev); static int ne_probe1(struct net_device *dev, int ioaddr); static int ne_open(struct net_device *dev); static int ne_close(struct net_device *dev); @@ -113,9 +112,10 @@ E2010 starts at 0x100 and ends at 0x4000. E2010-x starts at 0x100 and ends at 0xffff. */ -int __init ne_probe(struct net_device *dev) +static int __init do_ne_probe(struct net_device *dev) { unsigned int base_addr = dev->base_addr; + int irq = dev->irq; SET_MODULE_OWNER(dev); @@ -135,7 +135,7 @@ if (ei_debug > 2) printk(KERN_DEBUG "ne_probe(): call ne_probe_cbus(base_addr=0x%x)\n", base_addr); - result = ne_probe_cbus(dev, hw, base_addr); + result = ne_probe_cbus(dev, hw, base_addr, irq); if (result != 0) ne2k_cbus_destroy(dev); @@ -156,13 +156,13 @@ if (hw && hw->hwtype) { const unsigned short *plist; for (plist = hw->portlist; *plist; plist++) - if (ne_probe_cbus(dev, hw, *plist) == 0) + if (ne_probe_cbus(dev, hw, *plist, irq) == 0) return 0; } else { for (hw = &ne2k_cbus_hwinfo_list[0]; hw->hwtype; hw++) { const unsigned short *plist; for (plist = hw->portlist; *plist; plist++) - if (ne_probe_cbus(dev, hw, *plist) == 0) + if (ne_probe_cbus(dev, hw, *plist, irq) == 0) return 0; } } @@ -174,7 +174,45 @@ return -ENODEV; } -static int __init ne_probe_cbus(struct net_device *dev, const struct ne2k_cbus_hwinfo *hw, int ioaddr) +static void cleanup_card(struct net_device *dev) +{ + const struct ne2k_cbus_region *rlist; + const struct ne2k_cbus_hwinfo *hw = ne2k_cbus_get_hwinfo((int)(dev->mem_start & NE2K_CBUS_HARDWARE_TYPE_MASK)); + + free_irq(dev->irq, dev); + for (rlist = hw->regionlist; rlist->range; rlist++) { + release_region(dev->base_addr + rlist->start, + rlist->range); + } + ne2k_cbus_destroy(dev); +} + +struct net_device * __init ne_probe(int unit) +{ + struct net_device *dev = alloc_ei_netdev(); + int err; + + if (!dev) + return ERR_PTR(-ENOMEM); + + sprintf(dev->name, "eth%d", unit); + netdev_boot_setup_check(dev); + + err = do_ne_probe(dev); + if (err) + goto out; + err = register_netdev(dev); + if (err) + goto out1; + return dev; +out1: + cleanup_card(dev); +out: + free_netdev(dev); + return ERR_PTR(err); +} + +static int __init ne_probe_cbus(struct net_device *dev, const struct ne2k_cbus_hwinfo *hw, int ioaddr, int irq) { if (ei_debug > 2) printk(KERN_DEBUG "ne_probe_cbus(): entered. (called from %p)\n", @@ -182,6 +220,7 @@ if (hw && hw->hwtype) { ne2k_cbus_set_hwtype(dev, hw, ioaddr); + dev->irq = irq; return ne_probe1(dev, ioaddr); } else { /* auto detect */ @@ -189,6 +228,7 @@ printk(KERN_DEBUG "ne_probe_cbus(): try to determine hardware types.\n"); for (hw = &ne2k_cbus_hwinfo_list[0]; hw->hwtype; hw++) { ne2k_cbus_set_hwtype(dev, hw, ioaddr); + dev->irq = irq; if (ne_probe1(dev, ioaddr) == 0) return 0; } @@ -301,11 +341,12 @@ if (ei_debug > 2) printk(" [CNET98EL-specific initialize..."); outb_p(E8390_NODMA | E8390_STOP, ioaddr + E8390_CMD); /* 0x20|0x1 */ + ret = -ENODEV; i = inb(ioaddr); if ((i & ~0x2) != (0x20 | 0x01)) - return -ENODEV; + goto err_out; if ((inb(ioaddr + 0x7) & 0x80) != 0x80) - return -ENODEV; + goto err_out; outb_p(E8390_RXOFF, ioaddr + EN0_RXCR); /* out(ioaddr+0xc, 0x20) */ /* outb_p(ENDCFG_WTS|ENDCFG_FT1|ENDCFG_LS, ioaddr+EN0_DCFG); */ outb_p(ENDCFG_WTS | 0x48, ioaddr + EN0_DCFG); /* 0x49 */ @@ -330,7 +371,7 @@ if (ei_debug > 2) printk("] "); printk("memory failure at %x\n", i); - return -ENODEV; + goto err_out; } if (ei_debug > 2) printk(" good..."); @@ -338,7 +379,7 @@ if (ei_debug > 2) printk("] "); printk("IRQ must be specified for C-NET(98)E/L. probe failed.\n"); - return -ENODEV; + goto err_out; } outb((dev->irq > 5) ? (dev->irq & 4):(dev->irq >> 1), ioaddr + (0x2 | 0x400)); outb(0x7e, ioaddr + (0x4 | 0x400)); @@ -457,14 +498,6 @@ goto err_out; } - /* Allocate dev->priv and fill in 8390 specific dev fields. */ - if (ethdev_init(dev)) - { - printk (" unable to get memory for dev->priv.\n"); - ret = -ENOMEM; - goto err_out; - } - /* Snarf the interrupt now. There's no point in waiting since we cannot share and the board will usually be enabled. */ ret = request_irq(dev->irq, ei_interrupt, 0, name, dev); @@ -501,6 +534,9 @@ ei_status.priv = 0; dev->open = &ne_open; dev->stop = &ne_close; +#ifdef CONFIG_NET_POLL_CONTROLLER + dev->poll_controller = ei_poll; +#endif NS8390_init(dev, 0); return 0; @@ -779,7 +815,7 @@ #ifdef MODULE #define MAX_NE_CARDS 4 /* Max number of NE cards per module */ -static struct net_device dev_ne[MAX_NE_CARDS]; +static struct net_device *dev_ne[MAX_NE_CARDS]; static int io[MAX_NE_CARDS]; static int irq[MAX_NE_CARDS]; static int bad[MAX_NE_CARDS]; /* 0xbad = bad sig or no reset ack */ @@ -806,26 +842,32 @@ int this_dev, found = 0; for (this_dev = 0; this_dev < MAX_NE_CARDS; this_dev++) { - struct net_device *dev = &dev_ne[this_dev]; + struct net_device *dev = alloc_ei_netdev(); + if (!dev) + break; dev->irq = irq[this_dev]; dev->mem_end = bad[this_dev]; dev->base_addr = io[this_dev]; dev->mem_start = hwtype[this_dev]; - dev->init = ne_probe; - if (register_netdev(dev) == 0) { - found++; - continue; - } - if (found != 0) { /* Got at least one. */ - return 0; + if (do_ne_probe(dev) == 0) { + if (register_netdev(dev) == 0) { + dev_ne[found++] = dev; + continue; + } + cleanup_card(dev); } + free_netdev(dev); + if (found) + break; if (io[this_dev] != 0) printk(KERN_WARNING "ne2k_cbus: No NE*000 card found at i/o = %#x\n", io[this_dev]); else - printk(KERN_NOTICE "ne2k_cbus: You must supply \"io=0xNNN\" value(s) for C-Bus cards.\n"); + printk(KERN_NOTICE "ne.c: You must supply \"io=0xNNN\" value(s) for ISA cards.\n"); return -ENXIO; } - return 0; + if (found) + return 0; + return -ENODEV; } void cleanup_module(void) @@ -833,18 +875,11 @@ int this_dev; for (this_dev = 0; this_dev < MAX_NE_CARDS; this_dev++) { - struct net_device *dev = &dev_ne[this_dev]; - if (dev->priv != NULL) { - const struct ne2k_cbus_region *rlist; - const struct ne2k_cbus_hwinfo *hw = ne2k_cbus_get_hwinfo((int)(dev->mem_start & NE2K_CBUS_HARDWARE_TYPE_MASK)); - - free_irq(dev->irq, dev); - for (rlist = hw->regionlist; rlist->range; rlist++) { - release_region(dev->base_addr + rlist->start, - rlist->range); - } + struct net_device *dev = dev_ne[this_dev]; + if (dev) { unregister_netdev(dev); - ne2k_cbus_destroy(dev); + cleanup_card(dev); + free_netdev(dev); } } } diff -Nru a/drivers/net/ne2k_cbus.h b/drivers/net/ne2k_cbus.h --- a/drivers/net/ne2k_cbus.h Thu Jan 22 18:59:23 2004 +++ b/drivers/net/ne2k_cbus.h Thu Jan 22 18:59:23 2004 @@ -477,5 +477,5 @@ } #endif -static int ne_probe_cbus(struct net_device *dev, const struct ne2k_cbus_hwinfo *hw, int ioaddr); +static int ne_probe_cbus(struct net_device *dev, const struct ne2k_cbus_hwinfo *hw, int ioaddr, int irq); /* End of ne2k_cbus.h */ diff -Nru a/drivers/net/ne3210.c b/drivers/net/ne3210.c --- a/drivers/net/ne3210.c Thu Jan 22 18:59:24 2004 +++ b/drivers/net/ne3210.c Thu Jan 22 18:59:24 2004 @@ -111,12 +111,6 @@ device->driver_data = dev; ioaddr = edev->base_addr; - if (ethdev_init (dev)) { - printk ("ne3210.c: unable to allocate memory for dev->priv!\n"); - retval = -ENOMEM; - goto out; - } - if (!request_region(ioaddr, NE3210_IO_EXTENT, dev->name)) { retval = -EBUSY; goto out; @@ -211,6 +205,9 @@ dev->open = &ne3210_open; dev->stop = &ne3210_close; +#ifdef CONFIG_NET_POLL_CONTROLLER + dev->poll_controller = ei_poll; +#endif dev->if_port = ifmap_val[port_index]; if ((retval = register_netdev (dev))) @@ -356,24 +353,6 @@ .remove = __devexit_p (ne3210_eisa_remove), }, }; - -#ifdef MODULE -#if 0 -#define MAX_NE3210_CARDS 4 /* Max number of NE3210 cards per module */ -static struct net_device dev_ne3210[MAX_NE3210_CARDS]; -static int io[MAX_NE3210_CARDS]; -static int irq[MAX_NE3210_CARDS]; -static int mem[MAX_NE3210_CARDS]; - -MODULE_PARM(io, "1-" __MODULE_STRING(MAX_NE3210_CARDS) "i"); -MODULE_PARM(irq, "1-" __MODULE_STRING(MAX_NE3210_CARDS) "i"); -MODULE_PARM(mem, "1-" __MODULE_STRING(MAX_NE3210_CARDS) "i"); -MODULE_PARM_DESC(io, "I/O base address(es)"); -MODULE_PARM_DESC(irq, "IRQ number(s)"); -MODULE_PARM_DESC(mem, "memory base address(es)"); -#endif -#endif /* MODULE */ - MODULE_DESCRIPTION("NE3210 EISA Ethernet driver"); MODULE_LICENSE("GPL"); diff -Nru a/drivers/net/net_init.c b/drivers/net/net_init.c --- a/drivers/net/net_init.c Thu Jan 22 18:59:23 2004 +++ b/drivers/net/net_init.c Thu Jan 22 18:59:23 2004 @@ -73,23 +73,28 @@ struct net_device *alloc_netdev(int sizeof_priv, const char *mask, void (*setup)(struct net_device *)) { + void *p; struct net_device *dev; int alloc_size; - /* ensure 32-byte alignment of the private area */ - alloc_size = sizeof (*dev) + sizeof_priv + 31; + /* ensure 32-byte alignment of both the device and private area */ - dev = (struct net_device *) kmalloc (alloc_size, GFP_KERNEL); - if (dev == NULL) - { - printk(KERN_ERR "alloc_dev: Unable to allocate device memory.\n"); + alloc_size = (sizeof(struct net_device) + 31) & ~31; + alloc_size += sizeof_priv + 31; + + p = kmalloc (alloc_size, GFP_KERNEL); + if (!p) { + printk(KERN_ERR "alloc_dev: Unable to allocate device.\n"); return NULL; } - memset(dev, 0, alloc_size); + memset(p, 0, alloc_size); + + dev = (struct net_device *)(((long)p + 31) & ~31); + dev->padded = (char *)dev - (char *)p; if (sizeof_priv) - dev->priv = (void *) (((long)(dev + 1) + 31) & ~31); + dev->priv = netdev_priv(dev); setup(dev); strcpy(dev->name, mask); diff -Nru a/drivers/net/netconsole.c b/drivers/net/netconsole.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/net/netconsole.c Thu Jan 22 18:59:27 2004 @@ -0,0 +1,126 @@ +/* + * linux/drivers/net/netconsole.c + * + * Copyright (C) 2001 Ingo Molnar + * + * This file contains the implementation of an IRQ-safe, crash-safe + * kernel console implementation that outputs kernel messages to the + * network. + * + * Modification history: + * + * 2001-09-17 started by Ingo Molnar. + * 2003-08-11 2.6 port by Matt Mackall + * simplified options + * generic card hooks + * works non-modular + * 2003-09-07 rewritten with netpoll api + */ + +/**************************************************************** + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + ****************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +MODULE_AUTHOR("Maintainer: Matt Mackall "); +MODULE_DESCRIPTION("Console driver for network interfaces"); +MODULE_LICENSE("GPL"); + +static char config[256]; +module_param_string(netconsole, config, 256, 0); +MODULE_PARM_DESC(netconsole, " netconsole=[src-port]@[src-ip]/[dev],[tgt-port]@/[tgt-macaddr]\n"); + +static struct netpoll np = { + .name = "netconsole", + .dev_name = "eth0", + .local_port = 6665, + .remote_port = 6666, + .remote_mac = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, +}; +static int configured = 0; + +#define MAX_PRINT_CHUNK 1000 + +static void write_msg(struct console *con, const char *msg, unsigned int len) +{ + int frag, left; + unsigned long flags; + + if (!np.dev) + return; + + local_irq_save(flags); + + for(left = len; left; ) { + frag = min(left, MAX_PRINT_CHUNK); + netpoll_send_udp(&np, msg, frag); + msg += frag; + left -= frag; + } + + local_irq_restore(flags); +} + +static struct console netconsole = { + .flags = CON_ENABLED | CON_PRINTBUFFER, + .write = write_msg +}; + +static void option_setup(char *opt) +{ + configured = !netpoll_parse_options(&np, opt); +} + +__setup("netconsole=", option_setup); + +static int init_netconsole(void) +{ + if(strlen(config)) + option_setup(config); + + if(!configured) { + printk("netconsole: not configured, aborting\n"); + return -EINVAL; + } + + if(netpoll_setup(&np)) + return -EINVAL; + + register_console(&netconsole); + printk(KERN_INFO "netconsole: network logging started\n"); + return 0; +} + +static void cleanup_netconsole(void) +{ + unregister_console(&netconsole); + netpoll_cleanup(&np); +} + +module_init(init_netconsole); +module_exit(cleanup_netconsole); diff -Nru a/drivers/net/ni5010.c b/drivers/net/ni5010.c --- a/drivers/net/ni5010.c Thu Jan 22 18:59:25 2004 +++ b/drivers/net/ni5010.c Thu Jan 22 18:59:25 2004 @@ -82,7 +82,7 @@ #ifndef FULL_IODETECT /* A zero-terminated list of I/O addresses to be probed. */ -static unsigned int ni5010_portlist[] __initdata = +static unsigned int ports[] __initdata = { 0x300, 0x320, 0x340, 0x360, 0x380, 0x3a0, 0 }; #endif @@ -95,13 +95,11 @@ struct ni5010_local { struct net_device_stats stats; int o_pkt_size; - int i_pkt_size; spinlock_t lock; }; /* Index to functions, as function prototypes. */ -extern int ni5010_probe(struct net_device *dev); static int ni5010_probe1(struct net_device *dev, int ioaddr); static int ni5010_open(struct net_device *dev); static int ni5010_send_packet(struct sk_buff *skb, struct net_device *dev); @@ -120,38 +118,58 @@ static void dump_packet(void *buf, int len); static void ni5010_show_registers(struct net_device *dev); +static int io; +static int irq; -int __init ni5010_probe(struct net_device *dev) +struct net_device * __init ni5010_probe(int unit) { + struct net_device *dev = alloc_etherdev(sizeof(struct ni5010_local)); int *port; - int base_addr = dev->base_addr; + int err = 0; - PRINTK2((KERN_DEBUG "%s: Entering ni5010_probe\n", dev->name)); + if (!dev) + return ERR_PTR(-ENOMEM); - SET_MODULE_OWNER(dev); + if (unit >= 0) { + sprintf(dev->name, "eth%d", unit); + netdev_boot_setup_check(dev); + io = dev->base_addr; + irq = dev->irq; + } - if (base_addr > 0x1ff) /* Check a single specified location. */ - return ni5010_probe1(dev, base_addr); - else if (base_addr != 0) /* Don't probe at all. */ - return -ENXIO; + PRINTK2((KERN_DEBUG "%s: Entering ni5010_probe\n", dev->name)); + SET_MODULE_OWNER(dev); + + if (io > 0x1ff) { /* Check a single specified location. */ + err = ni5010_probe1(dev, io); + } else if (io != 0) { /* Don't probe at all. */ + err = -ENXIO; + } else { #ifdef FULL_IODETECT - for (int ioaddr=0x200; ioaddr<0x400; ioaddr+=0x20) { - if (check_region(ioaddr, NI5010_IO_EXTENT)) - continue; - if (ni5010_probe1(dev, ioaddr) == 0) - return 0; - } + for (io=0x200; io<0x400 && ni5010_probe1(dev, io) ; io+=0x20) + ; + if (io == 0x400) + err = -ENODEV; + #else - for (port = ni5010_portlist; *port; port++) { - int ioaddr = *port; - if (check_region(ioaddr, NI5010_IO_EXTENT)) - continue; - if (ni5010_probe1(dev, ioaddr) == 0) - return 0; - } + for (port = ports; *port && ni5010_probe1(dev, *port); port++) + ; + if (!*port) + err = -ENODEV; #endif /* FULL_IODETECT */ - return -ENODEV; + } + if (err) + goto out; + err = register_netdev(dev); + if (err) + goto out1; + return dev; +out1: + release_region(dev->base_addr, NI5010_IO_EXTENT); +out: + free_netdev(dev); + return ERR_PTR(err); } static inline int rd_port(int ioaddr) @@ -188,9 +206,17 @@ static int __init ni5010_probe1(struct net_device *dev, int ioaddr) { static unsigned version_printed; + struct ni5010_local *lp; int i; unsigned int data = 0; int boguscount = 40; + int err = -ENODEV; + + dev->base_addr = ioaddr; + dev->irq = irq; + + if (!request_region(ioaddr, NI5010_IO_EXTENT, boardname)) + return -EBUSY; /* * This is no "official" probe method, I've rather tested which @@ -205,36 +231,40 @@ * * - Andreas */ - + PRINTK2((KERN_DEBUG "%s: entering ni5010_probe1(%#3x)\n", dev->name, ioaddr)); - if (inb(ioaddr+0) == 0xff) return -ENODEV; + if (inb(ioaddr+0) == 0xff) + goto out; while ( (rd_port(ioaddr) & rd_port(ioaddr) & rd_port(ioaddr) & rd_port(ioaddr) & rd_port(ioaddr) & rd_port(ioaddr)) != 0xff) { - if (boguscount-- == 0) return -ENODEV; + if (boguscount-- == 0) + goto out; } PRINTK2((KERN_DEBUG "%s: I/O #1 passed!\n", dev->name)); for (i=0; i<32; i++) if ( (data = rd_port(ioaddr)) != 0xff) break; - if (data==0xff) return -ENODEV; + if (data==0xff) + goto out; PRINTK2((KERN_DEBUG "%s: I/O #2 passed!\n", dev->name)); - if ( (data == SA_ADDR0) && - (rd_port(ioaddr) == SA_ADDR1) && - (rd_port(ioaddr) == SA_ADDR2) ) { - for (i=0; i<4; i++) rd_port(ioaddr); - if ( (rd_port(ioaddr) != NI5010_MAGICVAL1) || - (rd_port(ioaddr) != NI5010_MAGICVAL2) ) { - return -ENODEV; - } - } else return -ENODEV; - + if ((data != SA_ADDR0) || (rd_port(ioaddr) != SA_ADDR1) || + (rd_port(ioaddr) != SA_ADDR2)) + goto out; + + for (i=0; i<4; i++) + rd_port(ioaddr); + + if ( (rd_port(ioaddr) != NI5010_MAGICVAL1) || + (rd_port(ioaddr) != NI5010_MAGICVAL2) ) + goto out; + PRINTK2((KERN_DEBUG "%s: I/O #3 passed!\n", dev->name)); if (NI5010_DEBUG && version_printed++ == 0) @@ -267,8 +297,9 @@ PRINTK2((KERN_DEBUG "%s: I/O #6 passed!\n", dev->name)); if (dev->irq == 0) { + err = -EAGAIN; printk(KERN_WARNING "%s: no IRQ found!\n", dev->name); - return -EAGAIN; + goto out; } PRINTK2((KERN_DEBUG "%s: I/O #7 passed!\n", dev->name)); } else if (dev->irq == 2) { @@ -278,19 +309,9 @@ PRINTK2((KERN_DEBUG "%s: I/O #9 passed!\n", dev->name)); /* DMA is not supported (yet?), so no use detecting it */ + lp = (struct ni5010_local*)dev->priv; - if (dev->priv == NULL) { - struct ni5010_local* lp; - - dev->priv = kmalloc(sizeof(struct ni5010_local), GFP_KERNEL|GFP_DMA); - if (dev->priv == NULL) { - printk(KERN_WARNING "%s: Failed to allocate private memory\n", dev->name); - return -ENOMEM; - } - - lp = (struct ni5010_local*)dev->priv; - spin_lock_init(&lp->lock); - } + spin_lock_init(&lp->lock); PRINTK2((KERN_DEBUG "%s: I/O #10 passed!\n", dev->name)); @@ -315,9 +336,6 @@ } printk("// bufsize rcv/xmt=%d/%d\n", bufsize_rcv, NI5010_BUFSIZE); memset(dev->priv, 0, sizeof(struct ni5010_local)); - - /* Grab the region so we can find another board if autoIRQ fails. */ - request_region(ioaddr, NI5010_IO_EXTENT, boardname); dev->open = ni5010_open; dev->stop = ni5010_close; @@ -327,9 +345,6 @@ dev->tx_timeout = ni5010_timeout; dev->watchdog_timeo = HZ/20; - /* Fill in the fields of the device structure with ethernet values. */ - ether_setup(dev); - dev->flags &= ~IFF_MULTICAST; /* Multicast doesn't work */ /* Shut up the ni5010 */ @@ -345,6 +360,9 @@ printk(KERN_INFO "Join the NI5010 driver development team!\n"); printk(KERN_INFO "Mail to a.mohr@mailto.de or jvbest@wi.leidenuniv.nl\n"); return 0; +out: + release_region(dev->base_addr, NI5010_IO_EXTENT); + return err; } /* @@ -513,6 +531,7 @@ int ioaddr = dev->base_addr; unsigned char rcv_stat; struct sk_buff *skb; + int i_pkt_size; PRINTK2((KERN_DEBUG "%s: entering ni5010_rx()\n", dev->name)); @@ -532,17 +551,17 @@ outb(0xff, EDLC_RCLR); /* Clear the interrupt */ - lp->i_pkt_size = inw(IE_RCNT); - if (lp->i_pkt_size > ETH_FRAME_LEN || lp->i_pkt_size < 10 ) { + i_pkt_size = inw(IE_RCNT); + if (i_pkt_size > ETH_FRAME_LEN || i_pkt_size < 10 ) { PRINTK((KERN_DEBUG "%s: Packet size error, packet size = %#4.4x\n", - dev->name, lp->i_pkt_size)); + dev->name, i_pkt_size)); lp->stats.rx_errors++; lp->stats.rx_length_errors++; return; } /* Malloc up new buffer. */ - skb = dev_alloc_skb(lp->i_pkt_size + 3); + skb = dev_alloc_skb(i_pkt_size + 3); if (skb == NULL) { printk(KERN_WARNING "%s: Memory squeeze, dropping packet.\n", dev->name); lp->stats.rx_dropped++; @@ -555,7 +574,7 @@ /* Read packet into buffer */ outb(MM_MUX, IE_MMODE); /* Rcv buffer to system bus */ outw(0, IE_GP); /* Seek to beginning of packet */ - insb(IE_RBUF, skb_put(skb, lp->i_pkt_size), lp->i_pkt_size); + insb(IE_RBUF, skb_put(skb, i_pkt_size), i_pkt_size); if (NI5010_DEBUG >= 4) dump_packet(skb->data, skb->len); @@ -564,10 +583,10 @@ netif_rx(skb); dev->last_rx = jiffies; lp->stats.rx_packets++; - lp->stats.rx_bytes += lp->i_pkt_size; + lp->stats.rx_bytes += i_pkt_size; PRINTK2((KERN_DEBUG "%s: Received packet, size=%#4.4x\n", - dev->name, lp->i_pkt_size)); + dev->name, i_pkt_size)); } @@ -697,10 +716,10 @@ if (NI5010_DEBUG > 3) dump_packet(buf, length); - buf_offs = NI5010_BUFSIZE - length - pad; - lp->o_pkt_size = length + pad; + buf_offs = NI5010_BUFSIZE - length - pad; spin_lock_irqsave(&lp->lock, flags); + lp->o_pkt_size = length + pad; outb(0, EDLC_RMASK); /* Mask all receive interrupts */ outb(0, IE_MMODE); /* Put Xmit buffer on system bus */ @@ -745,9 +764,7 @@ } #ifdef MODULE -static struct net_device dev_ni5010; -static int io; -static int irq; +static struct net_device *dev_ni5010; MODULE_PARM(io, "i"); MODULE_PARM(irq, "i"); @@ -756,8 +773,6 @@ int init_module(void) { - int result; - PRINTK2((KERN_DEBUG "%s: entering init_module\n", boardname)); /* if(io <= 0 || irq == 0){ @@ -771,29 +786,18 @@ } PRINTK2((KERN_DEBUG "%s: init_module irq=%#2x, io=%#3x\n", boardname, irq, io)); - dev_ni5010.irq=irq; - dev_ni5010.base_addr=io; - dev_ni5010.init=ni5010_probe; - if ((result = register_netdev(&dev_ni5010)) != 0) { - PRINTK((KERN_WARNING "%s: register_netdev returned %d.\n", - boardname, result)); - return -EIO; - } + dev_ni5010 = ni5010_probe(-1); + if (IS_ERR(dev_ni5010)) + return PTR_ERR(dev_ni5010); return 0; } -void -cleanup_module(void) +void cleanup_module(void) { PRINTK2((KERN_DEBUG "%s: entering cleanup_module\n", boardname)); - - unregister_netdev(&dev_ni5010); - - release_region(dev_ni5010.base_addr, NI5010_IO_EXTENT); - if (dev_ni5010.priv != NULL){ - kfree(dev_ni5010.priv); - dev_ni5010.priv = NULL; - } + unregister_netdev(dev_ni5010); + release_region(dev_ni5010->base_addr, NI5010_IO_EXTENT); + free_netdev(dev_ni5010); } #endif /* MODULE */ MODULE_LICENSE("GPL"); diff -Nru a/drivers/net/ni52.c b/drivers/net/ni52.c --- a/drivers/net/ni52.c Thu Jan 22 18:59:25 2004 +++ b/drivers/net/ni52.c Thu Jan 22 18:59:25 2004 @@ -354,50 +354,76 @@ memset((char *)p->scb,0,sizeof(struct scb_struct)); } +/* set: io,irq,memstart,memend or set it when calling insmod */ +static int irq=9; +static int io=0x300; +static long memstart; /* e.g 0xd0000 */ +static long memend; /* e.g 0xd4000 */ + /********************************************** * probe the ni5210-card */ -int __init ni52_probe(struct net_device *dev) +struct net_device * __init ni52_probe(int unit) { -#ifndef MODULE - int *port; + struct net_device *dev = alloc_etherdev(sizeof(struct priv)); static int ports[] = {0x300, 0x280, 0x360 , 0x320 , 0x340, 0}; -#endif - int base_addr = dev->base_addr; - - SET_MODULE_OWNER(dev); + int *port; + int err = 0; - if (base_addr > 0x1ff) /* Check a single specified location. */ - return ni52_probe1(dev, base_addr); - else if (base_addr > 0) /* Don't probe at all. */ - return -ENXIO; + if (!dev) + return ERR_PTR(-ENOMEM); -#ifdef MODULE - printk("%s: no autoprobing allowed for modules.\n",dev->name); -#else - for (port = ports; *port; port++) { - int ioaddr = *port; - dev->base_addr = ioaddr; - if (ni52_probe1(dev, ioaddr) == 0) - return 0; + if (unit >= 0) { + sprintf(dev->name, "eth%d", unit); + netdev_boot_setup_check(dev); + io = dev->base_addr; + irq = dev->irq; + memstart = dev->mem_start; + memend = dev->mem_end; } -#ifdef FULL_IO_PROBE - for(dev->base_addr=0x200; dev->base_addr<0x400; dev->base_addr+=8) - if (ni52_probe1(dev, dev->base_addr) == 0) - return 0; -#endif + SET_MODULE_OWNER(dev); + if (io > 0x1ff) { /* Check a single specified location. */ + err = ni52_probe1(dev, io); + } else if (io > 0) { /* Don't probe at all. */ + err = -ENXIO; + } else { + for (port = ports; *port && ni52_probe1(dev, *port) ; port++) + ; + if (*port) + goto got_it; +#ifdef FULL_IO_PROBE + for (io = 0x200; io < 0x400 && ni52_probe1(dev, io); io += 8) + ; + if (io < 0x400) + goto got_it; #endif - - dev->base_addr = base_addr; - return -ENODEV; + err = -ENODEV; + } + if (err) + goto out; +got_it: + err = register_netdev(dev); + if (err) + goto out1; + return dev; +out1: + release_region(dev->base_addr, NI52_TOTAL_SIZE); +out: + free_netdev(dev); + return ERR_PTR(err); } static int __init ni52_probe1(struct net_device *dev,int ioaddr) { int i, size, retval; + dev->base_addr = ioaddr; + dev->irq = irq; + dev->mem_start = memstart; + dev->mem_end = memend; + if (!request_region(ioaddr, NI52_TOTAL_SIZE, dev->name)) return -EBUSY; @@ -416,7 +442,7 @@ goto out; } - printk("%s: NI5210 found at %#3lx, ",dev->name,dev->base_addr); + printk(KERN_INFO "%s: NI5210 found at %#3lx, ",dev->name,dev->base_addr); /* * check (or search) IO-Memory, 8K and 16K @@ -469,13 +495,6 @@ dev->mem_end = dev->mem_start + size; /* set mem_end showed by 'ifconfig' */ #endif - dev->priv = (void *) kmalloc(sizeof(struct priv),GFP_KERNEL); - if(dev->priv == NULL) { - printk("%s: Ooops .. can't allocate private driver memory.\n",dev->name); - retval = -ENOMEM; - goto out; - } - /* warning: we don't free it on errors */ memset((char *) dev->priv,0,sizeof(struct priv)); ((struct priv *) (dev->priv))->memtop = isa_bus_to_virt(dev->mem_start) + size; @@ -503,8 +522,6 @@ if(!dev->irq) { printk("?autoirq, Failed to detect IRQ line!\n"); - kfree(dev->priv); - dev->priv = NULL; retval = -EAGAIN; goto out; } @@ -526,8 +543,6 @@ dev->if_port = 0; - ether_setup(dev); - return 0; out: release_region(ioaddr, NI52_TOTAL_SIZE); @@ -1295,13 +1310,7 @@ } #ifdef MODULE -static struct net_device dev_ni52; - -/* set: io,irq,memstart,memend or set it when calling insmod */ -static int irq=9; -static int io=0x300; -static long memstart; /* e.g 0xd0000 */ -static long memend; /* e.g 0xd4000 */ +static struct net_device *dev_ni52; MODULE_PARM(io, "i"); MODULE_PARM(irq, "i"); @@ -1318,22 +1327,17 @@ printk("ni52: Autoprobing not allowed for modules.\nni52: Set symbols 'io' 'irq' 'memstart' and 'memend'\n"); return -ENODEV; } - dev_ni52.init = ni52_probe; - dev_ni52.irq = irq; - dev_ni52.base_addr = io; - dev_ni52.mem_end = memend; - dev_ni52.mem_start = memstart; - if (register_netdev(&dev_ni52) != 0) - return -EIO; + dev_ni52 = ni52_probe(-1); + if (IS_ERR(dev_ni52)) + return PTR_ERR(dev_ni52); return 0; } void cleanup_module(void) { - release_region(dev_ni52.base_addr, NI52_TOTAL_SIZE); - unregister_netdev(&dev_ni52); - kfree(dev_ni52.priv); - dev_ni52.priv = NULL; + unregister_netdev(dev_ni52); + release_region(dev_ni52->base_addr, NI52_TOTAL_SIZE); + free_netdev(dev_ni52); } #endif /* MODULE */ diff -Nru a/drivers/net/ni65.c b/drivers/net/ni65.c --- a/drivers/net/ni65.c Thu Jan 22 18:59:24 2004 +++ b/drivers/net/ni65.c Thu Jan 22 18:59:24 2004 @@ -343,29 +343,64 @@ return 0; } +static void cleanup_card(struct net_device *dev) +{ + struct priv *p = (struct priv *) dev->priv; + disable_dma(dev->dma); + free_dma(dev->dma); + release_region(dev->base_addr, cards[p->cardno].total_size); + ni65_free_buffer(p); +} + +/* set: io,irq,dma or set it when calling insmod */ +static int irq; +static int io; +static int dma; + /* * Probe The Card (not the lance-chip) */ -#ifdef MODULE -static -#endif -int __init ni65_probe(struct net_device *dev) +struct net_device * __init ni65_probe(int unit) { - int *port; + struct net_device *dev = alloc_etherdev(0); static int ports[] = {0x360,0x300,0x320,0x340, 0}; + int *port; + int err = 0; - if (dev->base_addr > 0x1ff) /* Check a single specified location. */ - return ni65_probe1(dev, dev->base_addr); - else if (dev->base_addr > 0) /* Don't probe at all. */ - return -ENXIO; + if (!dev) + return ERR_PTR(-ENOMEM); - for (port = ports; *port; port++) - { - if (ni65_probe1(dev, *port) == 0) - return 0; - } - - return -ENODEV; + if (unit >= 0) { + sprintf(dev->name, "eth%d", unit); + netdev_boot_setup_check(dev); + irq = dev->irq; + dma = dev->dma; + } else { + dev->base_addr = io; + } + + if (dev->base_addr > 0x1ff) { /* Check a single specified location. */ + err = ni65_probe1(dev, dev->base_addr); + } else if (dev->base_addr > 0) { /* Don't probe at all. */ + err = -ENXIO; + } else { + for (port = ports; *port && ni65_probe1(dev, *port); port++) + ; + if (!*port) + err = -ENODEV; + } + if (err) + goto out; + + err = register_netdev(dev); + if (err) + goto out1; + return dev; +out1: + cleanup_card(dev); +out: + free_netdev(dev); + return ERR_PTR(err); } /* @@ -377,6 +412,9 @@ struct priv *p; unsigned long flags; + dev->irq = irq; + dev->dma = dma; + for(i=0;iwatchdog_timeo = HZ/2; dev->get_stats = ni65_get_stats; dev->set_multicast_list = set_multicast_list; - - ether_setup(dev); - return 0; /* everything is OK */ } @@ -1213,12 +1248,7 @@ } #ifdef MODULE -static struct net_device dev_ni65 = { .base_addr = 0x360, .irq = 9, .init = ni65_probe }; - -/* set: io,irq,dma or set it when calling insmod */ -static int irq; -static int io; -static int dma; +static struct net_device *dev_ni65; MODULE_PARM(irq, "i"); MODULE_PARM(io, "i"); @@ -1229,26 +1259,15 @@ int init_module(void) { - dev_ni65.irq = irq; - dev_ni65.dma = dma; - dev_ni65.base_addr = io; - if (register_netdev(&dev_ni65) != 0) - return -EIO; - return 0; + dev_ni65 = ni65_probe(-1); + return IS_ERR(dev_ni65) ? PTR_ERR(dev_ni65) : 0; } void cleanup_module(void) { - struct priv *p; - p = (struct priv *) dev_ni65.priv; - if(!p) - BUG(); - disable_dma(dev_ni65.dma); - free_dma(dev_ni65.dma); - unregister_netdev(&dev_ni65); - release_region(dev_ni65.base_addr,cards[p->cardno].total_size); - ni65_free_buffer(p); - dev_ni65.priv = NULL; + unregister_netdev(dev_ni65); + cleanup_card(dev_ni65); + free_netdev(dev_ni65); } #endif /* MODULE */ diff -Nru a/drivers/net/ns83820.c b/drivers/net/ns83820.c --- a/drivers/net/ns83820.c Thu Jan 22 18:59:26 2004 +++ b/drivers/net/ns83820.c Thu Jan 22 18:59:26 2004 @@ -374,19 +374,6 @@ #define LINK_DOWN 0x02 #define LINK_UP 0x04 -#define __kick_rx(dev) writel(CR_RXE, dev->base + CR) - -#define kick_rx(dev) do { \ - dprintk("kick_rx: maybe kicking\n"); \ - if (test_and_clear_bit(0, &dev->rx_info.idle)) { \ - dprintk("actually kicking\n"); \ - writel(dev->rx_info.phy_descs + (4 * DESC_SIZE * dev->rx_info.next_rx), dev->base + RXDP); \ - if (dev->rx_info.next_rx == dev->rx_info.next_empty) \ - printk(KERN_DEBUG "%s: uh-oh: next_rx == next_empty???\n", dev->net_dev.name);\ - __kick_rx(dev); \ - } \ -} while(0) - #ifdef USE_64BIT_ADDR #define HW_ADDR_LEN 8 #define desc_addr_set(desc, addr) \ @@ -438,7 +425,6 @@ struct ns83820 { - struct net_device net_dev; /* must be first */ struct net_device_stats stats; u8 *base; @@ -478,6 +464,29 @@ struct timer_list tx_watchdog; }; +static inline struct ns83820 *PRIV(struct net_device *dev) +{ + return netdev_priv(dev); +} + +#define __kick_rx(dev) writel(CR_RXE, dev->base + CR) + +static inline void kick_rx(struct net_device *ndev) +{ + struct ns83820 *dev = PRIV(ndev); + dprintk("kick_rx: maybe kicking\n"); + if (test_and_clear_bit(0, &dev->rx_info.idle)) { + dprintk("actually kicking\n"); + writel(dev->rx_info.phy_descs + + (4 * DESC_SIZE * dev->rx_info.next_rx), + dev->base + RXDP); + if (dev->rx_info.next_rx == dev->rx_info.next_empty) + printk(KERN_DEBUG "%s: uh-oh: next_rx == next_empty???\n", + ndev->name); + __kick_rx(dev); + } +} + //free = (tx_done_idx + NR_TX_DESC-2 - free_idx) % NR_TX_DESC #define start_tx_okay(dev) \ (((NR_TX_DESC-2 + dev->tx_done_idx - dev->tx_free_idx) % NR_TX_DESC) > MIN_TX_DESC_FREE) @@ -546,15 +555,16 @@ return 0; } -static inline int rx_refill(struct ns83820 *dev, int gfp) +static inline int rx_refill(struct net_device *ndev, int gfp) { + struct ns83820 *dev = PRIV(ndev); unsigned i; unsigned long flags = 0; if (unlikely(nr_rx_empty(dev) <= 2)) return 0; - dprintk("rx_refill(%p)\n", dev); + dprintk("rx_refill(%p)\n", ndev); if (gfp == GFP_ATOMIC) spin_lock_irqsave(&dev->rx_info.lock, flags); for (i=0; idev = &dev->net_dev; + skb->dev = ndev; if (gfp != GFP_ATOMIC) spin_lock_irqsave(&dev->rx_info.lock, flags); res = ns83820_add_rx_skb(dev, skb); @@ -587,20 +597,21 @@ return i ? 0 : -ENOMEM; } -static void FASTCALL(rx_refill_atomic(struct ns83820 *dev)); -static void rx_refill_atomic(struct ns83820 *dev) +static void FASTCALL(rx_refill_atomic(struct net_device *ndev)); +static void rx_refill_atomic(struct net_device *ndev) { - rx_refill(dev, GFP_ATOMIC); + rx_refill(ndev, GFP_ATOMIC); } /* REFILL */ static inline void queue_refill(void *_dev) { - struct ns83820 *dev = _dev; + struct net_device *ndev = _dev; + struct ns83820 *dev = PRIV(ndev); - rx_refill(dev, GFP_KERNEL); + rx_refill(ndev, GFP_KERNEL); if (dev->rx_info.up) - kick_rx(dev); + kick_rx(ndev); } static inline void clear_rx_desc(struct ns83820 *dev, unsigned i) @@ -608,9 +619,10 @@ build_rx_desc(dev, dev->rx_info.descs + (DESC_SIZE * i), 0, 0, CMDSTS_OWN, 0); } -static void FASTCALL(phy_intr(struct ns83820 *dev)); -static void phy_intr(struct ns83820 *dev) +static void FASTCALL(phy_intr(struct net_device *ndev)); +static void phy_intr(struct net_device *ndev) { + struct ns83820 *dev = PRIV(ndev); static char *speeds[] = { "10", "100", "1000", "1000(?)", "1000F" }; u32 cfg, new_cfg; u32 tbisr, tanar, tanlpar; @@ -688,27 +700,28 @@ if (newlinkstate & LINK_UP && dev->linkstate != newlinkstate) { - netif_start_queue(&dev->net_dev); - netif_wake_queue(&dev->net_dev); + netif_start_queue(ndev); + netif_wake_queue(ndev); printk(KERN_INFO "%s: link now %s mbps, %s duplex and up.\n", - dev->net_dev.name, + ndev->name, speeds[speed], fullduplex ? "full" : "half"); } else if (newlinkstate & LINK_DOWN && dev->linkstate != newlinkstate) { - netif_stop_queue(&dev->net_dev); - printk(KERN_INFO "%s: link now down.\n", dev->net_dev.name); + netif_stop_queue(ndev); + printk(KERN_INFO "%s: link now down.\n", ndev->name); } dev->linkstate = newlinkstate; } -static int ns83820_setup_rx(struct ns83820 *dev) +static int ns83820_setup_rx(struct net_device *ndev) { + struct ns83820 *dev = PRIV(ndev); unsigned i; int ret; - dprintk("ns83820_setup_rx(%p)\n", dev); + dprintk("ns83820_setup_rx(%p)\n", ndev); dev->rx_info.idle = 1; dev->rx_info.next_rx = 0; @@ -721,7 +734,7 @@ writel(0, dev->base + RXDP_HI); writel(dev->rx_info.phy_descs, dev->base + RXDP); - ret = rx_refill(dev, GFP_KERNEL); + ret = rx_refill(ndev, GFP_KERNEL); if (!ret) { dprintk("starting receiver\n"); /* prevent the interrupt handler from stomping on us */ @@ -734,7 +747,7 @@ dev->rx_info.up = 1; - phy_intr(dev); + phy_intr(ndev); /* Okay, let it rip */ spin_lock_irq(&dev->misc_lock); @@ -753,7 +766,7 @@ writel(1, dev->base + IER); spin_unlock_irq(&dev->misc_lock); - kick_rx(dev); + kick_rx(ndev); spin_unlock_irq(&dev->rx_info.lock); } @@ -793,37 +806,39 @@ } } -static void FASTCALL(ns83820_rx_kick(struct ns83820 *dev)); -static void ns83820_rx_kick(struct ns83820 *dev) +static void FASTCALL(ns83820_rx_kick(struct net_device *ndev)); +static void ns83820_rx_kick(struct net_device *ndev) { + struct ns83820 *dev = PRIV(ndev); /*if (nr_rx_empty(dev) >= NR_RX_DESC/4)*/ { if (dev->rx_info.up) { - rx_refill_atomic(dev); - kick_rx(dev); + rx_refill_atomic(ndev); + kick_rx(ndev); } } if (dev->rx_info.up && nr_rx_empty(dev) > NR_RX_DESC*3/4) schedule_work(&dev->tq_refill); else - kick_rx(dev); + kick_rx(ndev); if (dev->rx_info.idle) - printk(KERN_DEBUG "%s: BAD\n", dev->net_dev.name); + printk(KERN_DEBUG "%s: BAD\n", ndev->name); } /* rx_irq * */ -static void FASTCALL(rx_irq(struct ns83820 *dev)); -static void rx_irq(struct ns83820 *dev) +static void FASTCALL(rx_irq(struct net_device *ndev)); +static void rx_irq(struct net_device *ndev) { + struct ns83820 *dev = PRIV(ndev); struct rx_info *info = &dev->rx_info; unsigned next_rx; u32 cmdsts, *desc; unsigned long flags; int nr = 0; - dprintk("rx_irq(%p)\n", dev); + dprintk("rx_irq(%p)\n", ndev); dprintk("rxdp: %08x, descs: %08lx next_rx[%d]: %p next_empty[%d]: %p\n", readl(dev->base + RXDP), (long)(dev->rx_info.phy_descs), @@ -873,7 +888,7 @@ } else { skb->ip_summed = CHECKSUM_NONE; } - skb->protocol = eth_type_trans(skb, &dev->net_dev); + skb->protocol = eth_type_trans(skb, ndev); if (NET_RX_DROP == netif_rx(skb)) { netdev_mangle_me_harder_failed: dev->stats.rx_dropped ++; @@ -899,8 +914,9 @@ static void rx_action(unsigned long _dev) { - struct ns83820 *dev = (void *)_dev; - rx_irq(dev); + struct net_device *ndev = (void *)_dev; + struct ns83820 *dev = PRIV(ndev); + rx_irq(ndev); writel(ihr, dev->base + IHR); spin_lock_irq(&dev->misc_lock); @@ -908,8 +924,8 @@ writel(dev->IMR_cache, dev->base + IMR); spin_unlock_irq(&dev->misc_lock); - rx_irq(dev); - ns83820_rx_kick(dev); + rx_irq(ndev); + ns83820_rx_kick(ndev); } /* Packet Transmit code @@ -924,13 +940,14 @@ /* No spinlock needed on the transmit irq path as the interrupt handler is * serialized. */ -static void do_tx_done(struct ns83820 *dev) +static void do_tx_done(struct net_device *ndev) { + struct ns83820 *dev = PRIV(ndev); u32 cmdsts, tx_done_idx, *desc; spin_lock_irq(&dev->tx_lock); - dprintk("do_tx_done(%p)\n", dev); + dprintk("do_tx_done(%p)\n", ndev); tx_done_idx = dev->tx_done_idx; desc = dev->tx_descs + (tx_done_idx * DESC_SIZE); @@ -980,10 +997,10 @@ /* Allow network stack to resume queueing packets after we've * finished transmitting at least 1/4 of the packets in the queue. */ - if (netif_queue_stopped(&dev->net_dev) && start_tx_okay(dev)) { - dprintk("start_queue(%p)\n", dev); - netif_start_queue(&dev->net_dev); - netif_wake_queue(&dev->net_dev); + if (netif_queue_stopped(ndev) && start_tx_okay(dev)) { + dprintk("start_queue(%p)\n", ndev); + netif_start_queue(ndev); + netif_wake_queue(ndev); } spin_unlock_irq(&dev->tx_lock); } @@ -1015,9 +1032,9 @@ * while trying to track down a bug in either the zero copy code or * the tx fifo (hence the MAX_FRAG_LEN). */ -static int ns83820_hard_start_xmit(struct sk_buff *skb, struct net_device *_dev) +static int ns83820_hard_start_xmit(struct sk_buff *skb, struct net_device *ndev) { - struct ns83820 *dev = (struct ns83820 *)_dev; + struct ns83820 *dev = PRIV(ndev); u32 free_idx, cmdsts, extsts; int nr_free, nr_frags; unsigned tx_done_idx, last_idx; @@ -1033,10 +1050,10 @@ nr_frags = skb_shinfo(skb)->nr_frags; again: if (unlikely(dev->CFG_cache & CFG_LNKSTS)) { - netif_stop_queue(&dev->net_dev); + netif_stop_queue(ndev); if (unlikely(dev->CFG_cache & CFG_LNKSTS)) return 1; - netif_start_queue(&dev->net_dev); + netif_start_queue(ndev); } last_idx = free_idx = dev->tx_free_idx; @@ -1044,13 +1061,13 @@ nr_free = (tx_done_idx + NR_TX_DESC-2 - free_idx) % NR_TX_DESC; nr_free -= 1; if (nr_free <= nr_frags) { - dprintk("stop_queue - not enough(%p)\n", dev); - netif_stop_queue(&dev->net_dev); + dprintk("stop_queue - not enough(%p)\n", ndev); + netif_stop_queue(ndev); /* Check again: we may have raced with a tx done irq */ if (dev->tx_done_idx != tx_done_idx) { - dprintk("restart queue(%p)\n", dev); - netif_start_queue(&dev->net_dev); + dprintk("restart queue(%p)\n", ndev); + netif_start_queue(ndev); goto again; } return 1; @@ -1063,8 +1080,8 @@ nr_free -= nr_frags; if (nr_free < MIN_TX_DESC_FREE) { - dprintk("stop_queue - last entry(%p)\n", dev); - netif_stop_queue(&dev->net_dev); + dprintk("stop_queue - last entry(%p)\n", ndev); + netif_stop_queue(ndev); stopped = 1; } @@ -1136,10 +1153,10 @@ /* Check again: we may have raced with a tx done irq */ if (stopped && (dev->tx_done_idx != tx_done_idx) && start_tx_okay(dev)) - netif_start_queue(&dev->net_dev); + netif_start_queue(ndev); /* set the transmit start time to catch transmit timeouts */ - dev->net_dev.trans_start = jiffies; + ndev->trans_start = jiffies; return 0; } @@ -1161,9 +1178,9 @@ dev->stats.tx_carrier_errors += readl(base + 0x88) & 0xff; } -static struct net_device_stats *ns83820_get_stats(struct net_device *_dev) +static struct net_device_stats *ns83820_get_stats(struct net_device *ndev) { - struct ns83820 *dev = (void *)_dev; + struct ns83820 *dev = PRIV(ndev); /* somewhat overkill */ spin_lock_irq(&dev->misc_lock); @@ -1213,9 +1230,9 @@ return -EOPNOTSUPP; } -static int ns83820_ioctl(struct net_device *_dev, struct ifreq *rq, int cmd) +static int ns83820_ioctl(struct net_device *ndev, struct ifreq *rq, int cmd) { - struct ns83820 *dev = (struct ns83820 *)_dev; + struct ns83820 *dev = PRIV(ndev); switch(cmd) { case SIOCETHTOOL: @@ -1233,23 +1250,25 @@ spin_unlock(&dev->misc_lock); } -static void ns83820_do_isr(struct ns83820 *dev, u32 isr); +static void ns83820_do_isr(struct net_device *ndev, u32 isr); static irqreturn_t ns83820_irq(int foo, void *data, struct pt_regs *regs) { - struct ns83820 *dev = data; + struct net_device *ndev = data; + struct ns83820 *dev = PRIV(ndev); u32 isr; - dprintk("ns83820_irq(%p)\n", dev); + dprintk("ns83820_irq(%p)\n", ndev); dev->ihr = 0; isr = readl(dev->base + ISR); dprintk("irq: %08x\n", isr); - ns83820_do_isr(dev, isr); + ns83820_do_isr(ndev, isr); return IRQ_HANDLED; } -static void ns83820_do_isr(struct ns83820 *dev, u32 isr) +static void ns83820_do_isr(struct net_device *ndev, u32 isr) { + struct ns83820 *dev = PRIV(ndev); #ifdef DEBUG if (isr & ~(ISR_PHY | ISR_RXDESC | ISR_RXEARLY | ISR_RXOK | ISR_RXERR | ISR_TXIDLE | ISR_TXOK | ISR_TXDESC)) Dprintk("odd isr? 0x%08x\n", isr); @@ -1258,7 +1277,7 @@ if (ISR_RXIDLE & isr) { dev->rx_info.idle = 1; Dprintk("oh dear, we are idle\n"); - ns83820_rx_kick(dev); + ns83820_rx_kick(ndev); } if ((ISR_RXDESC | ISR_RXOK) & isr) { @@ -1270,12 +1289,12 @@ spin_unlock_irq(&dev->misc_lock); tasklet_schedule(&dev->rx_tasklet); - //rx_irq(dev); + //rx_irq(ndev); //writel(4, dev->base + IHR); } if ((ISR_RXIDLE | ISR_RXORN | ISR_RXDESC | ISR_RXOK | ISR_RXERR) & isr) - ns83820_rx_kick(dev); + ns83820_rx_kick(ndev); if (unlikely(ISR_RXSOVR & isr)) { //printk("overrun: rxsovr\n"); @@ -1297,7 +1316,7 @@ txdp -= dev->tx_phy_descs; dev->tx_idx = txdp / (DESC_SIZE * 4); if (dev->tx_idx >= NR_TX_DESC) { - printk(KERN_ALERT "%s: BUG -- txdp out of range\n", dev->net_dev.name); + printk(KERN_ALERT "%s: BUG -- txdp out of range\n", ndev->name); dev->tx_idx = 0; } /* The may have been a race between a pci originated read @@ -1313,7 +1332,7 @@ * work has accumulated */ if ((ISR_TXDESC | ISR_TXIDLE | ISR_TXOK | ISR_TXERR) & isr) { - do_tx_done(dev); + do_tx_done(ndev); /* Disable TxOk if there are no outstanding tx packets. */ @@ -1345,7 +1364,7 @@ /* PHY: Link up/down/negotiation state change */ if (unlikely(ISR_PHY & isr)) - phy_intr(dev); + phy_intr(ndev); #if 0 /* Still working on the interrupt mitigation strategy */ if (dev->ihr) @@ -1363,9 +1382,9 @@ Dprintk("okay!\n"); } -static int ns83820_stop(struct net_device *_dev) +static int ns83820_stop(struct net_device *ndev) { - struct ns83820 *dev = (struct ns83820 *)_dev; + struct ns83820 *dev = PRIV(ndev); /* FIXME: protect against interrupt handler? */ del_timer_sync(&dev->tx_watchdog); @@ -1392,10 +1411,9 @@ return 0; } -static void ns83820_do_isr(struct ns83820 *dev, u32 isr); -static void ns83820_tx_timeout(struct net_device *_dev) +static void ns83820_tx_timeout(struct net_device *ndev) { - struct ns83820 *dev = (struct ns83820 *)_dev; + struct ns83820 *dev = PRIV(ndev); u32 tx_done_idx, *desc; unsigned long flags; @@ -1405,7 +1423,7 @@ desc = dev->tx_descs + (tx_done_idx * DESC_SIZE); printk(KERN_INFO "%s: tx_timeout: tx_done_idx=%d free_idx=%d cmdsts=%08x\n", - dev->net_dev.name, + ndev->name, tx_done_idx, dev->tx_free_idx, le32_to_cpu(desc[DESC_CMDSTS])); #if defined(DEBUG) @@ -1413,17 +1431,17 @@ u32 isr; isr = readl(dev->base + ISR); printk("irq: %08x imr: %08x\n", isr, dev->IMR_cache); - ns83820_do_isr(dev, isr); + ns83820_do_isr(ndev, isr); } #endif - do_tx_done(dev); + do_tx_done(ndev); tx_done_idx = dev->tx_done_idx; desc = dev->tx_descs + (tx_done_idx * DESC_SIZE); printk(KERN_INFO "%s: after: tx_done_idx=%d free_idx=%d cmdsts=%08x\n", - dev->net_dev.name, + ndev->name, tx_done_idx, dev->tx_free_idx, le32_to_cpu(desc[DESC_CMDSTS])); local_irq_restore(flags); @@ -1431,7 +1449,8 @@ static void ns83820_tx_watch(unsigned long data) { - struct ns83820 *dev = (void *)data; + struct net_device *ndev = (void *)data; + struct ns83820 *dev = PRIV(ndev); #if defined(DEBUG) printk("ns83820_tx_watch: %u %u %d\n", @@ -1439,21 +1458,21 @@ ); #endif - if (time_after(jiffies, dev->net_dev.trans_start + 1*HZ) && + if (time_after(jiffies, ndev->trans_start + 1*HZ) && dev->tx_done_idx != dev->tx_free_idx) { printk(KERN_DEBUG "%s: ns83820_tx_watch: %u %u %d\n", - dev->net_dev.name, + ndev->name, dev->tx_done_idx, dev->tx_free_idx, atomic_read(&dev->nr_tx_skbs)); - ns83820_tx_timeout(&dev->net_dev); + ns83820_tx_timeout(ndev); } mod_timer(&dev->tx_watchdog, jiffies + 2*HZ); } -static int ns83820_open(struct net_device *_dev) +static int ns83820_open(struct net_device *ndev) { - struct ns83820 *dev = (struct ns83820 *)_dev; + struct ns83820 *dev = PRIV(ndev); unsigned i; u32 desc; int ret; @@ -1462,7 +1481,7 @@ writel(0, dev->base + PQCR); - ret = ns83820_setup_rx(dev); + ret = ns83820_setup_rx(ndev); if (ret) goto failed; @@ -1481,16 +1500,16 @@ writel(desc, dev->base + TXDP); init_timer(&dev->tx_watchdog); - dev->tx_watchdog.data = (unsigned long)dev; + dev->tx_watchdog.data = (unsigned long)ndev; dev->tx_watchdog.function = ns83820_tx_watch; mod_timer(&dev->tx_watchdog, jiffies + 2*HZ); - netif_start_queue(&dev->net_dev); /* FIXME: wait for phy to come up */ + netif_start_queue(ndev); /* FIXME: wait for phy to come up */ return 0; failed: - ns83820_stop(_dev); + ns83820_stop(ndev); return ret; } @@ -1513,28 +1532,28 @@ } } -static int ns83820_change_mtu(struct net_device *_dev, int new_mtu) +static int ns83820_change_mtu(struct net_device *ndev, int new_mtu) { if (new_mtu > RX_BUF_SIZE) return -EINVAL; - _dev->mtu = new_mtu; + ndev->mtu = new_mtu; return 0; } -static void ns83820_set_multicast(struct net_device *_dev) +static void ns83820_set_multicast(struct net_device *ndev) { - struct ns83820 *dev = (void *)_dev; + struct ns83820 *dev = PRIV(ndev); u8 *rfcr = dev->base + RFCR; u32 and_mask = 0xffffffff; u32 or_mask = 0; u32 val; - if (dev->net_dev.flags & IFF_PROMISC) + if (ndev->flags & IFF_PROMISC) or_mask |= RFCR_AAU | RFCR_AAM; else and_mask &= ~(RFCR_AAU | RFCR_AAM); - if (dev->net_dev.flags & IFF_ALLMULTI) + if (ndev->flags & IFF_ALLMULTI) or_mask |= RFCR_AAM; else and_mask &= ~RFCR_AAM; @@ -1547,14 +1566,15 @@ spin_unlock_irq(&dev->misc_lock); } -static void ns83820_run_bist(struct ns83820 *dev, const char *name, u32 enable, u32 done, u32 fail) +static void ns83820_run_bist(struct net_device *ndev, const char *name, u32 enable, u32 done, u32 fail) { + struct ns83820 *dev = PRIV(ndev); int timed_out = 0; long start; u32 status; int loops = 0; - dprintk("%s: start %s\n", dev->net_dev.name, name); + dprintk("%s: start %s\n", ndev->name, name); start = jiffies; @@ -1578,12 +1598,12 @@ if (status & fail) printk(KERN_INFO "%s: %s failed! (0x%08x & 0x%08x)\n", - dev->net_dev.name, name, status, fail); + ndev->name, name, status, fail); else if (timed_out) printk(KERN_INFO "%s: run_bist %s timed out! (%08x)\n", - dev->net_dev.name, name, status); + ndev->name, name, status); - dprintk("%s: done %s in %d loops\n", dev->net_dev.name, name, loops); + dprintk("%s: done %s in %d loops\n", ndev->name, name, loops); } #ifdef PHY_CODE_IS_FINISHED @@ -1706,8 +1726,9 @@ return data; } -static void ns83820_probe_phy(struct ns83820 *dev) +static void ns83820_probe_phy(struct net_device *ndev) { + struct ns83820 *dev = PRIV(ndev); static int first; int i; #define MII_PHYIDR1 0x02 @@ -1734,11 +1755,11 @@ b = ns83820_mii_read_reg(dev, i, MII_PHYIDR2); //printk("%s: phy %d: 0x%04x 0x%04x\n", - // dev->net_dev.name, i, a, b); + // ndev->name, i, a, b); for (j=0; j<0x16; j+=4) { dprintk("%s: [0x%02x] %04x %04x %04x %04x\n", - dev->net_dev.name, j, + ndev->name, j, ns83820_mii_read_reg(dev, i, 0 + j), ns83820_mii_read_reg(dev, i, 1 + j), ns83820_mii_read_reg(dev, i, 2 + j), @@ -1763,6 +1784,7 @@ static int __devinit ns83820_init_one(struct pci_dev *pci_dev, const struct pci_device_id *id) { + struct net_device *ndev; struct ns83820 *dev; long addr; int err; @@ -1778,7 +1800,8 @@ return -ENODEV; } - dev = (struct ns83820 *)alloc_etherdev((sizeof *dev) - (sizeof dev->net_dev)); + ndev = alloc_etherdev(sizeof(struct ns83820)); + dev = PRIV(ndev); err = -ENOMEM; if (!dev) goto out; @@ -1790,12 +1813,11 @@ dev->ee.cache = &dev->MEAR_cache; dev->ee.lock = &dev->misc_lock; - SET_MODULE_OWNER(dev->net_dev); - SET_NETDEV_DEV(&dev->net_dev, &pci_dev->dev); - dev->net_dev.priv = dev; + SET_MODULE_OWNER(ndev); + SET_NETDEV_DEV(ndev, &pci_dev->dev); - INIT_WORK(&dev->tq_refill, queue_refill, dev); - tasklet_init(&dev->rx_tasklet, rx_action, (unsigned long)dev); + INIT_WORK(&dev->tq_refill, queue_refill, ndev); + tasklet_init(&dev->rx_tasklet, rx_action, (unsigned long)ndev); err = pci_enable_device(pci_dev); if (err) { @@ -1829,55 +1851,63 @@ 0); err = request_irq(pci_dev->irq, ns83820_irq, SA_SHIRQ, - dev->net_dev.name, dev); + ndev->name, ndev); if (err) { printk(KERN_INFO "ns83820: unable to register irq %d\n", pci_dev->irq); goto out_disable; } - err = register_netdev(&dev->net_dev); - if (err) { - printk(KERN_INFO "ns83820: unable to register netdev: %d\n", err); + /* + * FIXME: we are holding rtnl_lock() over obscenely long area only + * because some of the setup code uses dev->name. It's Wrong(tm) - + * we should be using driver-specific names for all that stuff. + * For now that will do, but we really need to come back and kill + * most of the dev_alloc_name() users later. + */ + rtnl_lock(); + err = dev_alloc_name(ndev, ndev->name); + if (err < 0) { + printk(KERN_INFO "ns83820: unable to get netdev name: %d\n", err); goto out_free_irq; } printk("%s: ns83820.c: 0x22c: %08x, subsystem: %04x:%04x\n", - dev->net_dev.name, le32_to_cpu(readl(dev->base + 0x22c)), + ndev->name, le32_to_cpu(readl(dev->base + 0x22c)), pci_dev->subsystem_vendor, pci_dev->subsystem_device); - dev->net_dev.open = ns83820_open; - dev->net_dev.stop = ns83820_stop; - dev->net_dev.hard_start_xmit = ns83820_hard_start_xmit; - dev->net_dev.get_stats = ns83820_get_stats; - dev->net_dev.change_mtu = ns83820_change_mtu; - dev->net_dev.set_multicast_list = ns83820_set_multicast; - dev->net_dev.do_ioctl = ns83820_ioctl; - dev->net_dev.tx_timeout = ns83820_tx_timeout; - dev->net_dev.watchdog_timeo = 5 * HZ; + ndev->open = ns83820_open; + ndev->stop = ns83820_stop; + ndev->hard_start_xmit = ns83820_hard_start_xmit; + ndev->get_stats = ns83820_get_stats; + ndev->change_mtu = ns83820_change_mtu; + ndev->set_multicast_list = ns83820_set_multicast; + ndev->do_ioctl = ns83820_ioctl; + ndev->tx_timeout = ns83820_tx_timeout; + ndev->watchdog_timeo = 5 * HZ; - pci_set_drvdata(pci_dev, dev); + pci_set_drvdata(pci_dev, ndev); ns83820_do_reset(dev, CR_RST); /* Must reset the ram bist before running it */ writel(PTSCR_RBIST_RST, dev->base + PTSCR); - ns83820_run_bist(dev, "sram bist", PTSCR_RBIST_EN, + ns83820_run_bist(ndev, "sram bist", PTSCR_RBIST_EN, PTSCR_RBIST_DONE, PTSCR_RBIST_FAIL); - ns83820_run_bist(dev, "eeprom bist", PTSCR_EEBIST_EN, 0, + ns83820_run_bist(ndev, "eeprom bist", PTSCR_EEBIST_EN, 0, PTSCR_EEBIST_FAIL); - ns83820_run_bist(dev, "eeprom load", PTSCR_EELOAD_EN, 0, 0); + ns83820_run_bist(ndev, "eeprom load", PTSCR_EELOAD_EN, 0, 0); /* I love config registers */ dev->CFG_cache = readl(dev->base + CFG); if ((dev->CFG_cache & CFG_PCI64_DET)) { printk(KERN_INFO "%s: detected 64 bit PCI data bus.\n", - dev->net_dev.name); + ndev->name); /*dev->CFG_cache |= CFG_DATA64_EN;*/ if (!(dev->CFG_cache & CFG_DATA64_EN)) printk(KERN_INFO "%s: EEPROM did not enable 64 bit bus. Disabled.\n", - dev->net_dev.name); + ndev->name); } else dev->CFG_cache &= ~(CFG_DATA64_EN); @@ -1905,7 +1935,7 @@ /* setup optical transceiver if we have one */ if (dev->CFG_cache & CFG_TBI_EN) { printk(KERN_INFO "%s: enabling optical transceiver\n", - dev->net_dev.name); + ndev->name); writel(readl(dev->base + GPIOR) | 0x3e8, dev->base + GPIOR); /* setup auto negotiation feature advertisement */ @@ -1926,7 +1956,7 @@ dprintk("CFG: %08x\n", dev->CFG_cache); if (reset_phy) { - printk(KERN_INFO "%s: resetting phy\n", dev->net_dev.name); + printk(KERN_INFO "%s: resetting phy\n", ndev->name); writel(dev->CFG_cache | CFG_PHY_RST, dev->base + CFG); set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout((HZ+99)/100); @@ -1996,37 +2026,49 @@ /* Disable Wake On Lan */ writel(0, dev->base + WCSR); - ns83820_getmac(dev, dev->net_dev.dev_addr); + ns83820_getmac(dev, ndev->dev_addr); /* Yes, we support dumb IP checksum on transmit */ - dev->net_dev.features |= NETIF_F_SG; - dev->net_dev.features |= NETIF_F_IP_CSUM; + ndev->features |= NETIF_F_SG; + ndev->features |= NETIF_F_IP_CSUM; if (using_dac) { printk(KERN_INFO "%s: using 64 bit addressing.\n", - dev->net_dev.name); - dev->net_dev.features |= NETIF_F_HIGHDMA; + ndev->name); + ndev->features |= NETIF_F_HIGHDMA; } printk(KERN_INFO "%s: ns83820 v" VERSION ": DP83820 v%u.%u: %02x:%02x:%02x:%02x:%02x:%02x io=0x%08lx irq=%d f=%s\n", - dev->net_dev.name, + ndev->name, (unsigned)readl(dev->base + SRR) >> 8, (unsigned)readl(dev->base + SRR) & 0xff, - dev->net_dev.dev_addr[0], dev->net_dev.dev_addr[1], - dev->net_dev.dev_addr[2], dev->net_dev.dev_addr[3], - dev->net_dev.dev_addr[4], dev->net_dev.dev_addr[5], + ndev->dev_addr[0], ndev->dev_addr[1], + ndev->dev_addr[2], ndev->dev_addr[3], + ndev->dev_addr[4], ndev->dev_addr[5], addr, pci_dev->irq, - (dev->net_dev.features & NETIF_F_HIGHDMA) ? "h,sg" : "sg" + (ndev->features & NETIF_F_HIGHDMA) ? "h,sg" : "sg" ); #ifdef PHY_CODE_IS_FINISHED - ns83820_probe_phy(dev); + ns83820_probe_phy(ndev); #endif + err = register_netdevice(ndev); + if (err) { + printk(KERN_INFO "ns83820: unable to register netdev: %d\n", err); + goto out_cleanup; + } + rtnl_unlock(); + return 0; +out_cleanup: + writel(0, dev->base + IMR); /* paranoia */ + writel(0, dev->base + IER); + readl(dev->base + IER); out_free_irq: - free_irq(pci_dev->irq, dev); + rtnl_unlock(); + free_irq(pci_dev->irq, ndev); out_disable: if (dev->base) iounmap(dev->base); @@ -2034,7 +2076,7 @@ pci_free_consistent(pci_dev, 4 * DESC_SIZE * NR_RX_DESC, dev->rx_info.descs, dev->rx_info.phy_descs); pci_disable_device(pci_dev); out_free: - kfree(dev); + free_netdev(ndev); pci_set_drvdata(pci_dev, NULL); out: return err; @@ -2042,24 +2084,25 @@ static void __devexit ns83820_remove_one(struct pci_dev *pci_dev) { - struct ns83820 *dev = pci_get_drvdata(pci_dev); + struct net_device *ndev = pci_get_drvdata(pci_dev); + struct ns83820 *dev = PRIV(ndev); /* ok even if NULL */ - if (!dev) /* paranoia */ + if (!ndev) /* paranoia */ return; writel(0, dev->base + IMR); /* paranoia */ writel(0, dev->base + IER); readl(dev->base + IER); - unregister_netdev(&dev->net_dev); - free_irq(dev->pci_dev->irq, dev); + unregister_netdev(ndev); + free_irq(dev->pci_dev->irq, ndev); iounmap(dev->base); pci_free_consistent(dev->pci_dev, 4 * DESC_SIZE * NR_TX_DESC, dev->tx_descs, dev->tx_phy_descs); pci_free_consistent(dev->pci_dev, 4 * DESC_SIZE * NR_RX_DESC, dev->rx_info.descs, dev->rx_info.phy_descs); pci_disable_device(dev->pci_dev); - free_netdev(&dev->net_dev); + free_netdev(ndev); pci_set_drvdata(pci_dev, NULL); } diff -Nru a/drivers/net/oaknet.c b/drivers/net/oaknet.c --- a/drivers/net/oaknet.c Thu Jan 22 18:59:26 2004 +++ b/drivers/net/oaknet.c Thu Jan 22 18:59:26 2004 @@ -94,8 +94,8 @@ { register int i; int reg0, regd; - int ret; - struct net_device tmp, *dev = NULL; + int ret = -ENOMEM; + struct net_device *dev; #if 0 unsigned long ioaddr = OAKNET_IO_BASE; #else @@ -105,17 +105,14 @@ if (!ioaddr) return -ENOMEM; - /* - * This MUST happen here because of the nic_* macros - * which have an implicit dependency on dev->base_addr. - */ - tmp.base_addr = ioaddr; - dev = &tmp; + dev = alloc_ei_netdev(); + if (!dev) + goto out_unmap; ret = -EBUSY; if (!request_region(OAKNET_IO_BASE, OAKNET_IO_SIZE, name)) - goto out_unmap; + goto out_dev; /* Quick register check to see if the device is really there. */ @@ -144,17 +141,7 @@ goto out_region; } - /* - * We're not using the old-style probing API, so we have to allocate - * our own device structure. - */ - - dev = init_etherdev(NULL, 0); - ret = -ENOMEM; - if (!dev) - goto out_region; SET_MODULE_OWNER(dev); - oaknet_devs = dev; /* * This controller is on an embedded board, so the base address @@ -164,14 +151,6 @@ dev->base_addr = ioaddr; dev->irq = OAKNET_INT; - /* Allocate 8390-specific device-private area and fields. */ - - ret = -ENOMEM; - if (ethdev_init(dev)) { - printk(" unable to get memory for dev->priv.\n"); - goto out_dev; - } - /* * Disable all chip interrupts for now and ACK all pending * interrupts. @@ -186,7 +165,7 @@ if (request_irq(dev->irq, ei_interrupt, 0, name, dev)) { printk("%s: unable to request interrupt %d.\n", dev->name, dev->irq); - goto out_priv; + goto out_region; } /* Tell the world about what and where we've found. */ @@ -213,17 +192,24 @@ dev->open = oaknet_open; dev->stop = oaknet_close; +#ifdef CONFIG_NET_POLL_CONTROLLER + dev->poll_controller = ei_poll; +#endif NS8390_init(dev, FALSE); + ret = register_netdev(dev); + if (ret) + goto out_irq; + + oaknet_devs = dev; + return 0; - return (0); -out_priv: - kfree(dev->priv); -out_dev: - unregister_netdev(dev); - kfree(dev); +out_irq; + free_irq(dev->irq, dev); out_region: release_region(OAKNET_IO_BASE, OAKNET_IO_SIZE); +out_dev: + free_netdev(dev); out_unmap: iounmap(ioaddr); return ret; @@ -662,38 +648,18 @@ } /* - * Oak Ethernet module load interface. - */ -static int __init oaknet_init_module (void) -{ - if (oaknet_devs != NULL) - return (-EBUSY); - - return (oaknet_init()); -} - -/* * Oak Ethernet module unload interface. */ static void __exit oaknet_cleanup_module (void) { - if (oaknet_devs == NULL) - return; - - if (oaknet_devs->priv != NULL) { - int ioaddr = oaknet_devs->base_addr; - void *priv = oaknet_devs->priv; - free_irq(oaknet_devs->irq, oaknet_devs); - release_region(ioaddr, OAKNET_IO_SIZE); - iounmap(ioaddr); - unregister_netdev(oaknet_dev); - free_netdev(priv); - } - /* Convert to loop once driver supports multiple devices. */ - kfree(oaknet_devs); + unregister_netdev(oaknet_dev); + free_irq(oaknet_devs->irq, oaknet_devs); + release_region(oaknet_devs->base_addr, OAKNET_IO_SIZE); + iounmap(ioaddr); + free_netdev(oaknet_devs); } -module_init(oaknet_init_module); +module_init(oaknet_init); module_exit(oaknet_cleanup_module); MODULE_LICENSE("GPL"); diff -Nru a/drivers/net/pci-skeleton.c b/drivers/net/pci-skeleton.c --- a/drivers/net/pci-skeleton.c Thu Jan 22 18:59:23 2004 +++ b/drivers/net/pci-skeleton.c Thu Jan 22 18:59:23 2004 @@ -730,7 +730,7 @@ #endif pci_release_regions (pdev); err_out: - kfree (dev); + free_netdev (dev); DPRINTK ("EXIT, returning %d\n", rc); return rc; } diff -Nru a/drivers/net/pcmcia/3c574_cs.c b/drivers/net/pcmcia/3c574_cs.c --- a/drivers/net/pcmcia/3c574_cs.c Thu Jan 22 18:59:24 2004 +++ b/drivers/net/pcmcia/3c574_cs.c Thu Jan 22 18:59:24 2004 @@ -362,23 +362,17 @@ if (*linkp == NULL) return; - if (link->state & DEV_CONFIG) { + if (link->state & DEV_CONFIG) tc574_release(link); - if (link->state & DEV_STALE_CONFIG) - return; - } if (link->handle) pcmcia_deregister_client(link->handle); /* Unlink device structure, free bits */ *linkp = link->next; - if (link->dev) { + if (link->dev) unregister_netdev(dev); - free_netdev(dev); - } else - kfree(dev); - + free_netdev(dev); } /* tc574_detach */ /* @@ -557,21 +551,11 @@ { DEBUG(0, "3c574_release(0x%p)\n", link); - if (link->open) { - DEBUG(1, "3c574_cs: release postponed, '%s' still open\n", - link->dev->dev_name); - link->state |= DEV_STALE_CONFIG; - return; - } - pcmcia_release_configuration(link->handle); pcmcia_release_io(link->handle, &link->io); pcmcia_release_irq(link->handle, &link->irq); link->state &= ~DEV_CONFIG; - - if (link->state & DEV_STALE_CONFIG) - tc574_detach(link); } /* @@ -1300,8 +1284,7 @@ link->open--; netif_stop_queue(dev); del_timer_sync(&lp->media); - if (link->state & DEV_STALE_CONFIG) - tc574_release(link); + return 0; } diff -Nru a/drivers/net/pcmcia/3c589_cs.c b/drivers/net/pcmcia/3c589_cs.c --- a/drivers/net/pcmcia/3c589_cs.c Thu Jan 22 18:59:26 2004 +++ b/drivers/net/pcmcia/3c589_cs.c Thu Jan 22 18:59:26 2004 @@ -276,23 +276,17 @@ if (*linkp == NULL) return; - if (link->state & DEV_CONFIG) { + if (link->state & DEV_CONFIG) tc589_release(link); - if (link->state & DEV_STALE_CONFIG) - return; - } if (link->handle) pcmcia_deregister_client(link->handle); /* Unlink device structure, free bits */ *linkp = link->next; - if (link->dev) { + if (link->dev) unregister_netdev(dev); - free_netdev(dev); - } else - kfree(dev); - + free_netdev(dev); } /* tc589_detach */ /*====================================================================== @@ -433,21 +427,11 @@ { DEBUG(0, "3c589_release(0x%p)\n", link); - if (link->open) { - DEBUG(1, "3c589_cs: release postponed, '%s' still open\n", - link->dev->dev_name); - link->state |= DEV_STALE_CONFIG; - return; - } - pcmcia_release_configuration(link->handle); pcmcia_release_io(link->handle, &link->io); pcmcia_release_irq(link->handle, &link->irq); link->state &= ~DEV_CONFIG; - - if (link->state & DEV_STALE_CONFIG) - tc589_detach(link); } /*====================================================================== @@ -1076,8 +1060,6 @@ link->open--; netif_stop_queue(dev); del_timer_sync(&lp->media); - if (link->state & DEV_STALE_CONFIG) - tc589_release(link); return 0; } diff -Nru a/drivers/net/pcmcia/axnet_cs.c b/drivers/net/pcmcia/axnet_cs.c --- a/drivers/net/pcmcia/axnet_cs.c Thu Jan 22 18:59:25 2004 +++ b/drivers/net/pcmcia/axnet_cs.c Thu Jan 22 18:59:25 2004 @@ -119,7 +119,7 @@ static dev_info_t dev_info = "axnet_cs"; static dev_link_t *dev_list; -static int axdev_init(struct net_device *dev); +static void axdev_setup(struct net_device *dev); static void AX88190_init(struct net_device *dev, int startp); static int ax_open(struct net_device *dev); static int ax_close(struct net_device *dev); @@ -128,7 +128,6 @@ /*====================================================================*/ typedef struct axnet_dev_t { - struct net_device dev; /* so &dev == &axnet_dev_t */ dev_link_t link; dev_node_t node; caddr_t base; @@ -140,16 +139,10 @@ int flags; } axnet_dev_t; -/*====================================================================== - - We never need to do anything when a axnet device is "initialized" - by the net software, because we only register already-found cards. - -======================================================================*/ - -static int axnet_init(struct net_device *dev) +static inline axnet_dev_t *PRIV(struct net_device *dev) { - return 0; + void *p = (char *)netdev_priv(dev) + sizeof(struct ei_device); + return p; } /*====================================================================== @@ -170,12 +163,15 @@ DEBUG(0, "axnet_attach()\n"); - /* Create new ethernet device */ - info = kmalloc(sizeof(*info), GFP_KERNEL); - if (!info) return NULL; - memset(info, 0, sizeof(*info)); - link = &info->link; dev = &info->dev; - link->priv = info; + dev = alloc_netdev(sizeof(struct ei_device) + sizeof(axnet_dev_t), + "eth%d", axdev_setup); + + if (!dev) + return NULL; + + info = PRIV(dev); + link = &info->link; + link->priv = dev; link->irq.Attributes = IRQ_TYPE_EXCLUSIVE; link->irq.IRQInfo1 = IRQ_INFO2_VALID|IRQ_LEVEL_ID; if (irq_list[0] == -1) @@ -186,8 +182,6 @@ link->conf.Attributes = CONF_ENABLE_IRQ; link->conf.IntType = INT_MEMORY_AND_IO; - axdev_init(dev); - dev->init = &axnet_init; dev->open = &axnet_open; dev->stop = &axnet_close; dev->do_ioctl = &axnet_ioctl; @@ -226,7 +220,7 @@ static void axnet_detach(dev_link_t *link) { - axnet_dev_t *info = link->priv; + struct net_device *dev = link->priv; dev_link_t **linkp; DEBUG(0, "axnet_detach(0x%p)\n", link); @@ -237,23 +231,17 @@ if (*linkp == NULL) return; - if (link->state & DEV_CONFIG) { + if (link->state & DEV_CONFIG) axnet_release(link); - if (link->state & DEV_STALE_CONFIG) - return; - } if (link->handle) pcmcia_deregister_client(link->handle); /* Unlink device structure, free bits */ *linkp = link->next; - if (link->dev) { - unregister_netdev(&info->dev); - free_netdev(&info->dev); - } else - kfree(info); - + if (link->dev) + unregister_netdev(dev); + free_netdev(dev); } /* axnet_detach */ /*====================================================================== @@ -349,8 +337,8 @@ static void axnet_config(dev_link_t *link) { client_handle_t handle = link->handle; - axnet_dev_t *info = link->priv; - struct net_device *dev = &info->dev; + struct net_device *dev = link->priv; + axnet_dev_t *info = PRIV(dev); tuple_t tuple; cisparse_t parse; int i, j, last_ret, last_fn; @@ -425,15 +413,10 @@ CS_CHECK(RequestConfiguration, pcmcia_request_configuration(handle, &link->conf)); dev->irq = link->irq.AssignedIRQ; dev->base_addr = link->io.BasePort1; - if (register_netdev(dev) != 0) { - printk(KERN_NOTICE "axnet_cs: register_netdev() failed\n"); - goto failed; - } if (!get_prom(link)) { printk(KERN_NOTICE "axnet_cs: this is not an AX88190 card!\n"); printk(KERN_NOTICE "axnet_cs: use pcnet_cs instead.\n"); - unregister_netdev(dev); goto failed; } @@ -448,7 +431,6 @@ ei_status.block_output = &block_output; strcpy(info->node.dev_name, dev->name); - link->dev = &info->node; if (inb(dev->base_addr + AXNET_TEST) != 0) info->flags |= IS_AX88790; @@ -487,6 +469,12 @@ printk(KERN_NOTICE " No MII transceivers found!\n"); } + if (register_netdev(dev) != 0) { + printk(KERN_NOTICE "axnet_cs: register_netdev() failed\n"); + goto failed; + } + + link->dev = &info->node; link->state &= ~DEV_CONFIG_PENDING; return; @@ -510,21 +498,11 @@ { DEBUG(0, "axnet_release(0x%p)\n", link); - if (link->open) { - DEBUG(1, "axnet_cs: release postponed, '%s' still open\n", - ((axnet_dev_t *)(link->priv))->node.dev_name); - link->state |= DEV_STALE_CONFIG; - return; - } - pcmcia_release_configuration(link->handle); pcmcia_release_io(link->handle, &link->io); pcmcia_release_irq(link->handle, &link->irq); link->state &= ~DEV_CONFIG; - - if (link->state & DEV_STALE_CONFIG) - axnet_detach(link); } /*====================================================================== @@ -540,7 +518,7 @@ event_callback_args_t *args) { dev_link_t *link = args->client_data; - axnet_dev_t *info = link->priv; + struct net_device *dev = link->priv; DEBUG(2, "axnet_event(0x%06x)\n", event); @@ -548,7 +526,7 @@ case CS_EVENT_CARD_REMOVAL: link->state &= ~DEV_PRESENT; if (link->state & DEV_CONFIG) { - netif_device_detach(&info->dev); + netif_device_detach(dev); axnet_release(link); } break; @@ -562,7 +540,7 @@ case CS_EVENT_RESET_PHYSICAL: if (link->state & DEV_CONFIG) { if (link->open) - netif_device_detach(&info->dev); + netif_device_detach(dev); pcmcia_release_configuration(link->handle); } break; @@ -573,9 +551,9 @@ if (link->state & DEV_CONFIG) { pcmcia_request_configuration(link->handle, &link->conf); if (link->open) { - axnet_reset_8390(&info->dev); - AX88190_init(&info->dev, 1); - netif_device_attach(&info->dev); + axnet_reset_8390(dev); + AX88190_init(dev, 1); + netif_device_attach(dev); } } break; @@ -645,7 +623,7 @@ static int axnet_open(struct net_device *dev) { - axnet_dev_t *info = (axnet_dev_t *)dev; + axnet_dev_t *info = PRIV(dev); dev_link_t *link = &info->link; DEBUG(2, "axnet_open('%s')\n", dev->name); @@ -660,7 +638,7 @@ info->link_status = 0x00; init_timer(&info->watchdog); info->watchdog.function = &ei_watchdog; - info->watchdog.data = (u_long)info; + info->watchdog.data = (u_long)dev; info->watchdog.expires = jiffies + HZ; add_timer(&info->watchdog); @@ -671,7 +649,7 @@ static int axnet_close(struct net_device *dev) { - axnet_dev_t *info = (axnet_dev_t *)dev; + axnet_dev_t *info = PRIV(dev); dev_link_t *link = &info->link; DEBUG(2, "axnet_close('%s')\n", dev->name); @@ -682,8 +660,6 @@ link->open--; netif_stop_queue(dev); del_timer_sync(&info->watchdog); - if (link->state & DEV_STALE_CONFIG) - axnet_release(link); return 0; } /* axnet_close */ @@ -723,15 +699,15 @@ static irqreturn_t ei_irq_wrapper(int irq, void *dev_id, struct pt_regs *regs) { - axnet_dev_t *info = dev_id; - info->stale = 0; + struct net_device *dev = dev_id; + PRIV(dev)->stale = 0; return ax_interrupt(irq, dev_id, regs); } static void ei_watchdog(u_long arg) { - axnet_dev_t *info = (axnet_dev_t *)(arg); - struct net_device *dev = &info->dev; + struct net_device *dev = (struct net_device *)(arg); + axnet_dev_t *info = PRIV(dev); ioaddr_t nic_base = dev->base_addr; ioaddr_t mii_addr = nic_base + AXNET_MII_EEP; u_short link; @@ -801,7 +777,7 @@ static int axnet_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { - axnet_dev_t *info = (axnet_dev_t *)dev; + axnet_dev_t *info = PRIV(dev); u16 *data = (u16 *)&rq->ifr_data; ioaddr_t mii_addr = dev->base_addr + AXNET_MII_EEP; switch (cmd) { @@ -1050,14 +1026,7 @@ static int ax_open(struct net_device *dev) { unsigned long flags; - struct ei_device *ei_local = (struct ei_device *) dev->priv; - - /* This can't happen unless somebody forgot to call axdev_init(). */ - if (ei_local == NULL) - { - printk(KERN_EMERG "%s: ax_open passed a non-existent device!\n", dev->name); - return -ENXIO; - } + struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev); #ifdef HAVE_TX_TIMEOUT /* The card I/O part of the driver (e.g. 3c503) can hook a Tx timeout @@ -1083,7 +1052,7 @@ return 0; } -#define dev_lock(dev) (((struct ei_device *)(dev)->priv)->page_lock) +#define dev_lock(dev) (((struct ei_device *)netdev_priv(dev))->page_lock) /** * ax_close - shut down network device @@ -1117,7 +1086,7 @@ void ei_tx_timeout(struct net_device *dev) { long e8390_base = dev->base_addr; - struct ei_device *ei_local = (struct ei_device *) dev->priv; + struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev); int txsr, isr, tickssofar = jiffies - dev->trans_start; unsigned long flags; @@ -1163,7 +1132,7 @@ static int ei_start_xmit(struct sk_buff *skb, struct net_device *dev) { long e8390_base = dev->base_addr; - struct ei_device *ei_local = (struct ei_device *) dev->priv; + struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev); int length, send_length, output_page; unsigned long flags; u8 packet[ETH_ZLEN]; @@ -1309,7 +1278,7 @@ } e8390_base = dev->base_addr; - ei_local = (struct ei_device *) dev->priv; + ei_local = (struct ei_device *) netdev_priv(dev); /* * Protect the irq test too. @@ -1421,7 +1390,7 @@ static void ei_tx_err(struct net_device *dev) { long e8390_base = dev->base_addr; - struct ei_device *ei_local = (struct ei_device *) dev->priv; + struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev); unsigned char txsr = inb_p(e8390_base+EN0_TSR); unsigned char tx_was_aborted = txsr & (ENTSR_ABT+ENTSR_FU); @@ -1462,7 +1431,7 @@ static void ei_tx_intr(struct net_device *dev) { long e8390_base = dev->base_addr; - struct ei_device *ei_local = (struct ei_device *) dev->priv; + struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev); int status = inb(e8390_base + EN0_TSR); /* @@ -1543,7 +1512,7 @@ static void ei_receive(struct net_device *dev) { long e8390_base = dev->base_addr; - struct ei_device *ei_local = (struct ei_device *) dev->priv; + struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev); unsigned char rxing_page, this_frame, next_frame; unsigned short current_offset; int rx_pkt_count = 0; @@ -1663,7 +1632,7 @@ axnet_dev_t *info = (axnet_dev_t *)dev; long e8390_base = dev->base_addr; unsigned char was_txing, must_resend = 0; - struct ei_device *ei_local = (struct ei_device *) dev->priv; + struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev); /* * Record whether a Tx was in progress and then issue the @@ -1730,7 +1699,7 @@ static struct net_device_stats *get_stats(struct net_device *dev) { long ioaddr = dev->base_addr; - struct ei_device *ei_local = (struct ei_device *) dev->priv; + struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev); unsigned long flags; /* If the card is stopped, just return the present stats. */ @@ -1783,39 +1752,30 @@ } /** - * axdev_init - init rest of 8390 device struct + * axdev_setup - init rest of 8390 device struct * @dev: network device structure to init * * Initialize the rest of the 8390 device structure. Do NOT __init * this, as it is used by 8390 based modular drivers too. */ -static int axdev_init(struct net_device *dev) +static void axdev_setup(struct net_device *dev) { + struct ei_device *ei_local; if (ei_debug > 1) printk(version_8390); SET_MODULE_OWNER(dev); - if (dev->priv == NULL) - { - struct ei_device *ei_local; - dev->priv = kmalloc(sizeof(struct ei_device), GFP_KERNEL); - if (dev->priv == NULL) - return -ENOMEM; - memset(dev->priv, 0, sizeof(struct ei_device)); - ei_local = (struct ei_device *)dev->priv; - spin_lock_init(&ei_local->page_lock); - } + ei_local = (struct ei_device *)netdev_priv(dev); + spin_lock_init(&ei_local->page_lock); dev->hard_start_xmit = &ei_start_xmit; dev->get_stats = get_stats; dev->set_multicast_list = &set_multicast_list; ether_setup(dev); - - return 0; } /* This page of functions should be 8390 generic */ @@ -1831,9 +1791,9 @@ static void AX88190_init(struct net_device *dev, int startp) { - axnet_dev_t *info = (axnet_dev_t *)dev; + axnet_dev_t *info = PRIV(dev); long e8390_base = dev->base_addr; - struct ei_device *ei_local = (struct ei_device *) dev->priv; + struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev); int i; int endcfg = ei_local->word16 ? (0x48 | ENDCFG_WTS) : 0x48; @@ -1902,7 +1862,7 @@ int start_page) { long e8390_base = dev->base_addr; - struct ei_device *ei_local __attribute((unused)) = (struct ei_device *) dev->priv; + struct ei_device *ei_local __attribute((unused)) = (struct ei_device *) netdev_priv(dev); if (inb_p(e8390_base) & E8390_TRANS) { diff -Nru a/drivers/net/pcmcia/com20020_cs.c b/drivers/net/pcmcia/com20020_cs.c --- a/drivers/net/pcmcia/com20020_cs.c Thu Jan 22 18:59:25 2004 +++ b/drivers/net/pcmcia/com20020_cs.c Thu Jan 22 18:59:25 2004 @@ -145,20 +145,6 @@ dev_node_t node; } com20020_dev_t; -static void com20020_setup(struct net_device *dev) -{ - struct arcnet_local *lp = dev->priv; - - lp->timeout = timeout; - lp->backplane = backplane; - lp->clockp = clockp; - lp->clockm = clockm & 3; - lp->hw.owner = THIS_MODULE; - - /* fill in our module parameters as defaults */ - dev->dev_addr[0] = node; -} - /*====================================================================== com20020_attach() creates an "instance" of the driver, allocating @@ -187,14 +173,21 @@ if (!info) goto fail_alloc_info; - dev = alloc_netdev(sizeof(struct arcnet_local), "arc%d", - com20020_setup); + dev = alloc_arcdev(""); if (!dev) goto fail_alloc_dev; memset(info, 0, sizeof(struct com20020_dev_t)); memset(link, 0, sizeof(struct dev_link_t)); lp = dev->priv; + lp->timeout = timeout; + lp->backplane = backplane; + lp->clockp = clockp; + lp->clockm = clockm & 3; + lp->hw.owner = THIS_MODULE; + + /* fill in our module parameters as defaults */ + dev->dev_addr[0] = node; link->io.Attributes1 = IO_DATA_PATH_WIDTH_8; link->io.NumPorts1 = 16; @@ -270,11 +263,8 @@ dev = info->dev; - if (link->state & DEV_CONFIG) { + if (link->state & DEV_CONFIG) com20020_release(link); - if (link->state & DEV_STALE_CONFIG) - return; - } if (link->handle) pcmcia_deregister_client(link->handle); @@ -293,6 +283,8 @@ if (netif_running(dev)) dev->stop(dev); + + unregister_netdev(dev); /* * this is necessary because we register our IRQ separately @@ -300,10 +292,7 @@ */ if (dev->irq) free_irq(dev->irq, dev); - /* ...but I/O ports are done automatically by card services */ - - unregister_netdev(dev); } DEBUG(1,"kfree...\n"); @@ -447,21 +436,11 @@ DEBUG(0, "com20020_release(0x%p)\n", link); - if (link->open) { - DEBUG(1,"postpone...\n"); - DEBUG(1, "com20020_cs: release postponed, device stll open\n"); - link->state |= DEV_STALE_CONFIG; - return; - } - pcmcia_release_configuration(link->handle); pcmcia_release_io(link->handle, &link->io); pcmcia_release_irq(link->handle, &link->irq); link->state &= ~(DEV_CONFIG | DEV_RELEASE_PENDING); - - if (link->state & DEV_STALE_CONFIG) - com20020_detach(link); } /*====================================================================== diff -Nru a/drivers/net/pcmcia/fmvj18x_cs.c b/drivers/net/pcmcia/fmvj18x_cs.c --- a/drivers/net/pcmcia/fmvj18x_cs.c Thu Jan 22 18:59:26 2004 +++ b/drivers/net/pcmcia/fmvj18x_cs.c Thu Jan 22 18:59:26 2004 @@ -332,11 +332,8 @@ if (*linkp == NULL) return; - if (link->state & DEV_CONFIG) { + if (link->state & DEV_CONFIG) fmvj18x_release(link); - if (link->state & DEV_STALE_CONFIG) - return; - } /* Break the link with Card Services */ if (link->handle) @@ -344,12 +341,9 @@ /* Unlink device structure, free pieces */ *linkp = link->next; - if (link->dev) { + if (link->dev) unregister_netdev(dev); - free_netdev(dev); - } else - kfree(dev); - + free_netdev(dev); } /* fmvj18x_detach */ /*====================================================================*/ @@ -723,17 +717,6 @@ DEBUG(0, "fmvj18x_release(0x%p)\n", link); - /* - If the device is currently in use, we won't release until it - is actually closed. - */ - if (link->open) { - DEBUG(1, "fmvj18x_cs: release postponed, '%s' " - "still open\n", link->dev->dev_name); - link->state |= DEV_STALE_CONFIG; - return; - } - /* Don't bother checking to see if these succeed or not */ pcmcia_release_window(link->win); pcmcia_release_configuration(link->handle); @@ -741,9 +724,6 @@ pcmcia_release_irq(link->handle, &link->irq); link->state &= ~DEV_CONFIG; - - if (link->state & DEV_STALE_CONFIG) - fmvj18x_detach(link); } /*====================================================================*/ @@ -1251,8 +1231,6 @@ outb(INTR_OFF, ioaddr + LAN_CTRL); link->open--; - if (link->state & DEV_STALE_CONFIG) - fmvj18x_release(link); return 0; } /* fjn_close */ diff -Nru a/drivers/net/pcmcia/ibmtr_cs.c b/drivers/net/pcmcia/ibmtr_cs.c --- a/drivers/net/pcmcia/ibmtr_cs.c Thu Jan 22 18:59:25 2004 +++ b/drivers/net/pcmcia/ibmtr_cs.c Thu Jan 22 18:59:25 2004 @@ -125,8 +125,7 @@ static dev_link_t *dev_list; -extern int ibmtr_probe(struct net_device *dev); -extern int trdev_init(struct net_device *dev); +extern int ibmtr_probe_card(struct net_device *dev); extern irqreturn_t tok_interrupt (int irq, void *dev_id, struct pt_regs *regs); /*====================================================================*/ @@ -199,7 +198,6 @@ link->irq.Instance = info->dev = dev; - dev->init = &ibmtr_probe; SET_ETHTOOL_OPS(dev, &netdev_ethtool_ops); /* Register with Card Services */ @@ -253,22 +251,22 @@ return; dev = info->dev; + + if (link->dev) + unregister_netdev(dev); + { struct tok_info *ti = (struct tok_info *)dev->priv; del_timer_sync(&(ti->tr_timer)); } - if (link->state & DEV_CONFIG) { + if (link->state & DEV_CONFIG) ibmtr_release(link); - if (link->state & DEV_STALE_CONFIG) - return; - } if (link->handle) pcmcia_deregister_client(link->handle); /* Unlink device structure, free bits */ *linkp = link->next; - unregister_netdev(dev); free_netdev(dev); kfree(info); } /* ibmtr_detach */ @@ -369,7 +367,7 @@ Adapters Technical Reference" SC30-3585 for this info. */ ibmtr_hw_setup(dev, mmiobase); - i = register_netdev(dev); + i = ibmtr_probe_card(dev); if (i != 0) { printk(KERN_NOTICE "ibmtr_cs: register_netdev() failed\n"); @@ -410,13 +408,6 @@ DEBUG(0, "ibmtr_release(0x%p)\n", link); - if (link->open) { - DEBUG(1, "ibmtr_cs: release postponed, '%s' " - "still open\n", info->node.dev_name); - link->state |= DEV_STALE_CONFIG; - return; - } - pcmcia_release_configuration(link->handle); pcmcia_release_io(link->handle, &link->io); pcmcia_release_irq(link->handle, &link->irq); @@ -428,9 +419,6 @@ } link->state &= ~DEV_CONFIG; - - if (link->state & DEV_STALE_CONFIG) - ibmtr_detach(link); } /*====================================================================== @@ -482,7 +470,7 @@ if (link->state & DEV_CONFIG) { pcmcia_request_configuration(link->handle, &link->conf); if (link->open) { - (dev->init)(dev); + ibmtr_probe(dev); /* really? */ netif_device_attach(dev); } } diff -Nru a/drivers/net/pcmcia/nmclan_cs.c b/drivers/net/pcmcia/nmclan_cs.c --- a/drivers/net/pcmcia/nmclan_cs.c Thu Jan 22 18:59:23 2004 +++ b/drivers/net/pcmcia/nmclan_cs.c Thu Jan 22 18:59:23 2004 @@ -551,23 +551,17 @@ if (*linkp == NULL) return; - if (link->state & DEV_CONFIG) { + if (link->state & DEV_CONFIG) nmclan_release(link); - if (link->state & DEV_STALE_CONFIG) - return; - } if (link->handle) pcmcia_deregister_client(link->handle); /* Unlink device structure, free bits */ *linkp = link->next; - if (link->dev) { + if (link->dev) unregister_netdev(dev); - free_netdev(dev); - } else - kfree(dev); - + free_netdev(dev); } /* nmclan_detach */ /* ---------------------------------------------------------------------------- @@ -812,21 +806,11 @@ DEBUG(0, "nmclan_release(0x%p)\n", link); - if (link->open) { - DEBUG(1, "nmclan_cs: release postponed, '%s' " - "still open\n", link->dev->dev_name); - link->state |= DEV_STALE_CONFIG; - return; - } - pcmcia_release_configuration(link->handle); pcmcia_release_io(link->handle, &link->io); pcmcia_release_irq(link->handle, &link->irq); link->state &= ~DEV_CONFIG; - - if (link->state & DEV_STALE_CONFIG) - nmclan_detach(link); } /* ---------------------------------------------------------------------------- @@ -993,8 +977,6 @@ link->open--; netif_stop_queue(dev); - if (link->state & DEV_STALE_CONFIG) - nmclan_release(link); return 0; } /* mace_close */ diff -Nru a/drivers/net/pcmcia/pcnet_cs.c b/drivers/net/pcmcia/pcnet_cs.c --- a/drivers/net/pcmcia/pcnet_cs.c Thu Jan 22 18:59:26 2004 +++ b/drivers/net/pcmcia/pcnet_cs.c Thu Jan 22 18:59:26 2004 @@ -224,7 +224,6 @@ static hw_info_t dl10022_info = { 0, 0, 0, 0, IS_DL10022|HAS_MII }; typedef struct pcnet_dev_t { - struct net_device dev; /* so &dev == &pcnet_dev_t */ dev_link_t link; dev_node_t node; u_int flags; @@ -237,16 +236,10 @@ u_long mii_reset; } pcnet_dev_t; -/*====================================================================== - - We never need to do anything when a pcnet device is "initialized" - by the net software, because we only register already-found cards. - -======================================================================*/ - -static int pcnet_init(struct net_device *dev) +static inline pcnet_dev_t *PRIV(struct net_device *dev) { - return 0; + char *p = netdev_priv(dev); + return (pcnet_dev_t *)(p + sizeof(struct ei_device)); } /*====================================================================== @@ -268,11 +261,11 @@ DEBUG(0, "pcnet_attach()\n"); /* Create new ethernet device */ - info = kmalloc(sizeof(*info), GFP_KERNEL); - if (!info) return NULL; - memset(info, 0, sizeof(*info)); - link = &info->link; dev = &info->dev; - link->priv = info; + dev = __alloc_ei_netdev(sizeof(pcnet_dev_t)); + if (!dev) return NULL; + info = PRIV(dev); + link = &info->link; + link->priv = dev; link->irq.Attributes = IRQ_TYPE_EXCLUSIVE; link->irq.IRQInfo1 = IRQ_INFO2_VALID|IRQ_LEVEL_ID; @@ -284,9 +277,7 @@ link->conf.Attributes = CONF_ENABLE_IRQ; link->conf.IntType = INT_MEMORY_AND_IO; - ethdev_init(dev); SET_MODULE_OWNER(dev); - dev->init = &pcnet_init; dev->open = &pcnet_open; dev->stop = &pcnet_close; dev->set_config = &set_config; @@ -324,7 +315,7 @@ static void pcnet_detach(dev_link_t *link) { - pcnet_dev_t *info = link->priv; + struct net_device *dev = link->priv; dev_link_t **linkp; DEBUG(0, "pcnet_detach(0x%p)\n", link); @@ -335,23 +326,17 @@ if (*linkp == NULL) return; - if (link->state & DEV_CONFIG) { + if (link->state & DEV_CONFIG) pcnet_release(link); - if (link->state & DEV_STALE_CONFIG) - return; - } if (link->handle) pcmcia_deregister_client(link->handle); /* Unlink device structure, free bits */ *linkp = link->next; - if (link->dev) { - unregister_netdev(&info->dev); - free_netdev(&info->dev); - } else - kfree(info); - + if (link->dev) + unregister_netdev(dev); + free_netdev(dev); } /* pcnet_detach */ /*====================================================================== @@ -579,8 +564,8 @@ static void pcnet_config(dev_link_t *link) { client_handle_t handle = link->handle; - pcnet_dev_t *info = link->priv; - struct net_device *dev = &info->dev; + struct net_device *dev = link->priv; + pcnet_dev_t *info = PRIV(dev); tuple_t tuple; cisparse_t parse; int i, last_ret, last_fn, start_pg, stop_pg, cm_offset; @@ -782,17 +767,10 @@ static void pcnet_release(dev_link_t *link) { - pcnet_dev_t *info = link->priv; + pcnet_dev_t *info = PRIV(link->priv); DEBUG(0, "pcnet_release(0x%p)\n", link); - if (link->open) { - DEBUG(1, "pcnet_cs: release postponed, '%s' still open\n", - info->node.dev_name); - link->state |= DEV_STALE_CONFIG; - return; - } - if (info->flags & USE_SHMEM) { iounmap(info->base); pcmcia_release_window(link->win); @@ -802,9 +780,6 @@ pcmcia_release_irq(link->handle, &link->irq); link->state &= ~DEV_CONFIG; - - if (link->state & DEV_STALE_CONFIG) - pcnet_detach(link); } /*====================================================================== @@ -820,7 +795,7 @@ event_callback_args_t *args) { dev_link_t *link = args->client_data; - pcnet_dev_t *info = link->priv; + struct net_device *dev = link->priv; DEBUG(2, "pcnet_event(0x%06x)\n", event); @@ -828,7 +803,7 @@ case CS_EVENT_CARD_REMOVAL: link->state &= ~DEV_PRESENT; if (link->state & DEV_CONFIG) { - netif_device_detach(&info->dev); + netif_device_detach(dev); pcnet_release(link); } break; @@ -842,7 +817,7 @@ case CS_EVENT_RESET_PHYSICAL: if (link->state & DEV_CONFIG) { if (link->open) - netif_device_detach(&info->dev); + netif_device_detach(dev); pcmcia_release_configuration(link->handle); } break; @@ -853,9 +828,9 @@ if (link->state & DEV_CONFIG) { pcmcia_request_configuration(link->handle, &link->conf); if (link->open) { - pcnet_reset_8390(&info->dev); - NS8390_init(&info->dev, 1); - netif_device_attach(&info->dev); + pcnet_reset_8390(dev); + NS8390_init(dev, 1); + netif_device_attach(dev); } } break; @@ -1035,7 +1010,7 @@ static void set_misc_reg(struct net_device *dev) { ioaddr_t nic_base = dev->base_addr; - pcnet_dev_t *info = (pcnet_dev_t *)dev; + pcnet_dev_t *info = PRIV(dev); u_char tmp; if (info->flags & HAS_MISC_REG) { @@ -1065,7 +1040,7 @@ static void mii_phy_probe(struct net_device *dev) { - pcnet_dev_t *info = (pcnet_dev_t *)dev; + pcnet_dev_t *info = PRIV(dev); ioaddr_t mii_addr = dev->base_addr + DLINK_GPIO; int i; u_int tmp, phyid; @@ -1089,7 +1064,7 @@ static int pcnet_open(struct net_device *dev) { - pcnet_dev_t *info = (pcnet_dev_t *)dev; + pcnet_dev_t *info = PRIV(dev); dev_link_t *link = &info->link; DEBUG(2, "pcnet_open('%s')\n", dev->name); @@ -1106,7 +1081,7 @@ info->link_status = 0x00; init_timer(&info->watchdog); info->watchdog.function = &ei_watchdog; - info->watchdog.data = (u_long)info; + info->watchdog.data = (u_long)dev; info->watchdog.expires = jiffies + HZ; add_timer(&info->watchdog); @@ -1117,7 +1092,7 @@ static int pcnet_close(struct net_device *dev) { - pcnet_dev_t *info = (pcnet_dev_t *)dev; + pcnet_dev_t *info = PRIV(dev); dev_link_t *link = &info->link; DEBUG(2, "pcnet_close('%s')\n", dev->name); @@ -1128,8 +1103,6 @@ link->open--; netif_stop_queue(dev); del_timer_sync(&info->watchdog); - if (link->state & DEV_STALE_CONFIG) - pcnet_release(link); return 0; } /* pcnet_close */ @@ -1170,7 +1143,7 @@ static int set_config(struct net_device *dev, struct ifmap *map) { - pcnet_dev_t *info = (pcnet_dev_t *)dev; + pcnet_dev_t *info = PRIV(dev); if ((map->port != (u_char)(-1)) && (map->port != dev->if_port)) { if (!(info->flags & HAS_MISC_REG)) return -EOPNOTSUPP; @@ -1188,7 +1161,8 @@ static irqreturn_t ei_irq_wrapper(int irq, void *dev_id, struct pt_regs *regs) { - pcnet_dev_t *info = dev_id; + struct net_device *dev = dev_id; + pcnet_dev_t *info = PRIV(dev); info->stale = 0; ei_interrupt(irq, dev_id, regs); /* FIXME! Was it really ours? */ @@ -1197,8 +1171,8 @@ static void ei_watchdog(u_long arg) { - pcnet_dev_t *info = (pcnet_dev_t *)(arg); - struct net_device *dev = &info->dev; + struct net_device *dev = (struct net_device *)arg; + pcnet_dev_t *info = PRIV(dev); ioaddr_t nic_base = dev->base_addr; ioaddr_t mii_addr = nic_base + DLINK_GPIO; u_short link; @@ -1301,7 +1275,7 @@ static int ei_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { - pcnet_dev_t *info = (pcnet_dev_t *)dev; + pcnet_dev_t *info = PRIV(dev); u16 *data = (u16 *)&rq->ifr_data; ioaddr_t mii_addr = dev->base_addr + DLINK_GPIO; switch (cmd) { @@ -1412,7 +1386,7 @@ const u_char *buf, const int start_page) { ioaddr_t nic_base = dev->base_addr; - pcnet_dev_t *info = (pcnet_dev_t *)dev; + pcnet_dev_t *info = PRIV(dev); #ifdef PCMCIA_DEBUG int retries = 0; #endif @@ -1598,7 +1572,7 @@ int stop_pg, int cm_offset) { struct net_device *dev = link->priv; - pcnet_dev_t *info = link->priv; + pcnet_dev_t *info = PRIV(dev); win_req_t req; memreq_t mem; int i, window_size, offset, last_ret, last_fn; diff -Nru a/drivers/net/pcmcia/smc91c92_cs.c b/drivers/net/pcmcia/smc91c92_cs.c --- a/drivers/net/pcmcia/smc91c92_cs.c Thu Jan 22 18:59:26 2004 +++ b/drivers/net/pcmcia/smc91c92_cs.c Thu Jan 22 18:59:26 2004 @@ -411,23 +411,17 @@ if (*linkp == NULL) return; - if (link->state & DEV_CONFIG) { + if (link->state & DEV_CONFIG) smc91c92_release(link); - if (link->state & DEV_STALE_CONFIG) - return; - } if (link->handle) pcmcia_deregister_client(link->handle); /* Unlink device structure, free bits */ *linkp = link->next; - if (link->dev) { + if (link->dev) unregister_netdev(dev); - free_netdev(dev); - } else - kfree(dev); - + free_netdev(dev); } /* smc91c92_detach */ /*====================================================================*/ @@ -1070,13 +1064,6 @@ DEBUG(0, "smc91c92_release(0x%p)\n", link); - if (link->open) { - DEBUG(1, "smc91c92_cs: release postponed, '%s' still open\n", - link->dev->dev_name); - link->state |= DEV_STALE_CONFIG; - return; - } - pcmcia_release_configuration(link->handle); pcmcia_release_io(link->handle, &link->io); pcmcia_release_irq(link->handle, &link->irq); @@ -1088,9 +1075,6 @@ } link->state &= ~DEV_CONFIG; - - if (link->state & DEV_STALE_CONFIG) - smc91c92_detach(link); } /*====================================================================== @@ -1316,8 +1300,6 @@ link->open--; del_timer_sync(&smc->media); - if (link->state & DEV_STALE_CONFIG) - smc91c92_release(link); return 0; } /* smc_close */ diff -Nru a/drivers/net/pcmcia/xirc2ps_cs.c b/drivers/net/pcmcia/xirc2ps_cs.c --- a/drivers/net/pcmcia/xirc2ps_cs.c Thu Jan 22 18:59:24 2004 +++ b/drivers/net/pcmcia/xirc2ps_cs.c Thu Jan 22 18:59:24 2004 @@ -683,12 +683,9 @@ /* Unlink device structure, free it */ *linkp = link->next; - if (link->dev) { + if (link->dev) unregister_netdev(dev); - free_netdev(dev); - } else - kfree(dev); - + free_netdev(dev); } /* xirc2ps_detach */ /**************** diff -Nru a/drivers/net/pcnet32.c b/drivers/net/pcnet32.c --- a/drivers/net/pcnet32.c Thu Jan 22 18:59:24 2004 +++ b/drivers/net/pcnet32.c Thu Jan 22 18:59:24 2004 @@ -456,6 +456,14 @@ .reset = pcnet32_dwio_reset }; +#ifdef CONFIG_NET_POLL_CONTROLLER +static void pcnet32_poll_controller(struct net_device *dev) +{ + disable_irq(dev->irq); + pcnet32_interrupt(0, dev, NULL); + enable_irq(dev->irq); +} +#endif /* only probes for non-PCI devices, the rest are handled by @@ -805,12 +813,16 @@ dev->do_ioctl = &pcnet32_ioctl; dev->tx_timeout = pcnet32_tx_timeout; dev->watchdog_timeo = (5*HZ); +#ifdef CONFIG_NET_POLL_CONTROLLER + dev->poll_controller = pcnet32_poll_controller; +#endif + + /* Fill in the generic fields of the device structure. */ + if (register_netdev(dev)) + goto err_free_consistent; lp->next = pcnet32_dev; pcnet32_dev = dev; - - /* Fill in the generic fields of the device structure. */ - register_netdev(dev); printk(KERN_INFO "%s: registered as %s\n",dev->name, lp->name); cards_found++; return 0; diff -Nru a/drivers/net/plip.c b/drivers/net/plip.c --- a/drivers/net/plip.c Thu Jan 22 18:59:27 2004 +++ b/drivers/net/plip.c Thu Jan 22 18:59:27 2004 @@ -277,19 +277,11 @@ then calls us here. */ -static int +static void plip_init_netdev(struct net_device *dev) { struct net_local *nl = dev->priv; - printk(KERN_INFO "%s", version); - if (dev->irq != -1) - printk(KERN_INFO "%s: Parallel port at %#3lx, using IRQ %d.\n", - dev->name, dev->base_addr, dev->irq); - else - printk(KERN_INFO "%s: Parallel port at %#3lx, not using IRQ.\n", - dev->name, dev->base_addr); - /* Then, override parts of it */ dev->hard_start_xmit = plip_tx_packet; dev->open = plip_open; @@ -323,8 +315,6 @@ INIT_WORK(&nl->timer, (void (*)(void *))plip_timer_bh, dev); spin_lock_init(&nl->lock); - - return 0; } /* Bottom half handler for the delayed request. @@ -1282,14 +1272,13 @@ } sprintf(name, "plip%d", unit); - dev = alloc_netdev(sizeof(struct net_local), name, - ether_setup); + dev = alloc_etherdev(sizeof(struct net_local)); if (!dev) { printk(KERN_ERR "plip: memory squeeze\n"); return; } - dev->init = plip_init_netdev; + strcpy(dev->name, name); SET_MODULE_OWNER(dev); dev->irq = port->irq; @@ -1306,17 +1295,35 @@ if (!nl->pardev) { printk(KERN_ERR "%s: parport_register failed\n", name); - kfree(dev); + goto err_free_dev; return; } + plip_init_netdev(dev); + if (register_netdev(dev)) { printk(KERN_ERR "%s: network register failed\n", name); - kfree(dev); - } else { - dev_plip[unit++] = dev; + goto err_parport_unregister; } + + printk(KERN_INFO "%s", version); + if (dev->irq != -1) + printk(KERN_INFO "%s: Parallel port at %#3lx, " + "using IRQ %d.\n", + dev->name, dev->base_addr, dev->irq); + else + printk(KERN_INFO "%s: Parallel port at %#3lx, " + "not using IRQ.\n", + dev->name, dev->base_addr); + dev_plip[unit++] = dev; } + return; + +err_parport_unregister: + parport_unregister_device(nl->pardev); +err_free_dev: + free_netdev(dev); + return; } /* plip_detach() is called (by the parport code) when a port is diff -Nru a/drivers/net/ppp_generic.c b/drivers/net/ppp_generic.c --- a/drivers/net/ppp_generic.c Thu Jan 22 18:59:26 2004 +++ b/drivers/net/ppp_generic.c Thu Jan 22 18:59:26 2004 @@ -917,19 +917,14 @@ return err; } -static int -ppp_net_init(struct net_device *dev) +static void ppp_setup(struct net_device *dev) { dev->hard_header_len = PPP_HDRLEN; dev->mtu = PPP_MTU; - dev->hard_start_xmit = ppp_start_xmit; - dev->get_stats = ppp_net_stats; - dev->do_ioctl = ppp_net_ioctl; dev->addr_len = 0; dev->tx_queue_len = 3; dev->type = ARPHRD_PPP; dev->flags = IFF_POINTOPOINT | IFF_NOARP | IFF_MULTICAST; - return 0; } /* @@ -2272,23 +2267,13 @@ int i; ppp = kmalloc(sizeof(struct ppp), GFP_KERNEL); - if (ppp == 0) - goto err; - dev = kmalloc(sizeof(struct net_device), GFP_KERNEL); - if (dev == 0) - goto err; + if (!ppp) + goto out; + dev = alloc_netdev(0, "", ppp_setup); + if (!dev) + goto out1; memset(ppp, 0, sizeof(struct ppp)); - memset(dev, 0, sizeof(struct net_device)); - ret = -EEXIST; - down(&all_ppp_sem); - if (unit < 0) - unit = cardmap_find_first_free(all_ppp_units); - else if (cardmap_get(all_ppp_units, unit) != NULL) - goto err_unlock; /* unit already exists */ - - /* Initialize the new ppp unit */ - ppp->file.index = unit; ppp->mru = PPP_MRU; init_ppp_file(&ppp->file, INTERFACE); ppp->file.hdrlen = PPP_HDRLEN - 2; /* don't count proto bytes */ @@ -2301,20 +2286,29 @@ ppp->minseq = -1; skb_queue_head_init(&ppp->mrq); #endif /* CONFIG_PPP_MULTILINK */ - ppp->dev = dev; - dev->init = ppp_net_init; - sprintf(dev->name, "ppp%d", unit); dev->priv = ppp; - dev->destructor = free_netdev; - rtnl_lock(); - ret = register_netdevice(dev); - rtnl_unlock(); + dev->hard_start_xmit = ppp_start_xmit; + dev->get_stats = ppp_net_stats; + dev->do_ioctl = ppp_net_ioctl; + + ret = -EEXIST; + down(&all_ppp_sem); + if (unit < 0) + unit = cardmap_find_first_free(all_ppp_units); + else if (cardmap_get(all_ppp_units, unit) != NULL) + goto out2; /* unit already exists */ + + /* Initialize the new ppp unit */ + ppp->file.index = unit; + sprintf(dev->name, "ppp%d", unit); + + ret = register_netdev(dev); if (ret != 0) { printk(KERN_ERR "PPP: couldn't register device %s (%d)\n", dev->name, ret); - goto err_unlock; + goto out2; } atomic_inc(&ppp_unit_count); @@ -2323,14 +2317,13 @@ *retp = 0; return ppp; - err_unlock: +out2: up(&all_ppp_sem); - err: + free_netdev(dev); +out1: + kfree(ppp); +out: *retp = ret; - if (ppp) - kfree(ppp); - if (dev) - kfree(dev); return NULL; } @@ -2361,8 +2354,10 @@ ppp->dev = 0; ppp_unlock(ppp); /* This will call dev_close() for us. */ - if (dev) + if (dev) { unregister_netdev(dev); + free_netdev(dev); + } cardmap_set(&all_ppp_units, ppp->file.index, NULL); ppp->file.dead = 1; ppp->owner = NULL; diff -Nru a/drivers/net/pppoe.c b/drivers/net/pppoe.c --- a/drivers/net/pppoe.c Thu Jan 22 18:59:25 2004 +++ b/drivers/net/pppoe.c Thu Jan 22 18:59:26 2004 @@ -67,7 +67,6 @@ #include #include #include -#include #include #include #include diff -Nru a/drivers/net/r8169.c b/drivers/net/r8169.c --- a/drivers/net/r8169.c Thu Jan 22 18:59:25 2004 +++ b/drivers/net/r8169.c Thu Jan 22 18:59:25 2004 @@ -56,9 +56,11 @@ printk( "Assertion failed! %s,%s,%s,line=%d\n", \ #expr,__FILE__,__FUNCTION__,__LINE__); \ } +#define dprintk(fmt, args...) do { printk(PFX fmt, ## args) } while (0) #else #define assert(expr) do {} while (0) -#endif +#define dprintk(fmt, args...) do {} while (0) +#endif /* RTL8169_DEBUG */ /* media options */ #define MAX_UNITS 8 @@ -89,9 +91,12 @@ #define NUM_TX_DESC 64 /* Number of Tx descriptor registers */ #define NUM_RX_DESC 64 /* Number of Rx descriptor registers */ #define RX_BUF_SIZE 1536 /* Rx Buffer size */ +#define R8169_TX_RING_BYTES (NUM_TX_DESC * sizeof(struct TxDesc)) +#define R8169_RX_RING_BYTES (NUM_RX_DESC * sizeof(struct RxDesc)) #define RTL_MIN_IO_SIZE 0x80 -#define TX_TIMEOUT (6*HZ) +#define RTL8169_TX_TIMEOUT (6*HZ) +#define RTL8169_PHY_TIMEOUT (HZ) /* write/read MMIO register */ #define RTL_W8(reg, val8) writeb ((val8), ioaddr + (reg)) @@ -101,11 +106,35 @@ #define RTL_R16(reg) readw (ioaddr + (reg)) #define RTL_R32(reg) ((unsigned long) readl (ioaddr + (reg))) -static struct { +enum mac_version { + RTL_GIGA_MAC_VER_B = 0x00, + /* RTL_GIGA_MAC_VER_C = 0x03, */ + RTL_GIGA_MAC_VER_D = 0x01, + RTL_GIGA_MAC_VER_E = 0x02 +}; + +enum phy_version { + RTL_GIGA_PHY_VER_C = 0x03, /* PHY Reg 0x03 bit0-3 == 0x0000 */ + RTL_GIGA_PHY_VER_D = 0x04, /* PHY Reg 0x03 bit0-3 == 0x0000 */ + RTL_GIGA_PHY_VER_E = 0x05, /* PHY Reg 0x03 bit0-3 == 0x0000 */ + RTL_GIGA_PHY_VER_F = 0x06, /* PHY Reg 0x03 bit0-3 == 0x0001 */ + RTL_GIGA_PHY_VER_G = 0x07, /* PHY Reg 0x03 bit0-3 == 0x0002 */ +}; + + +#define _R(NAME,MAC,MASK) \ + { .name = NAME, .mac_version = MAC, .RxConfigMask = MASK } + +const static struct { const char *name; -} board_info[] __devinitdata = { - { -"RealTek RTL8169 Gigabit Ethernet"},}; + u8 mac_version; + u32 RxConfigMask; /* Clears the bits supported by this chip */ +} rtl_chip_info[] = { + _R("RTL8169", RTL_GIGA_MAC_VER_B, 0xff7e1880), + _R("RTL8169s/8110s", RTL_GIGA_MAC_VER_D, 0xff7e1880), + _R("RTL8169s/8110s", RTL_GIGA_MAC_VER_E, 0xff7e1880) +}; +#undef _R static struct pci_device_id rtl8169_pci_tbl[] = { {0x10ec, 0x8169, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, @@ -114,6 +143,8 @@ MODULE_DEVICE_TABLE(pci, rtl8169_pci_tbl); +static int rx_copybreak = 200; + enum RTL8169_registers { MAC0 = 0, /* Ethernet hardware address. */ MAR0 = 8, /* Multicast filter. */ @@ -242,14 +273,6 @@ TBILinkOK = 0x02000000, }; -const static struct { - const char *name; - u8 version; /* depend on RTL8169 docs */ - u32 RxConfigMask; /* should clear the bits supported by this chip */ -} rtl_chip_info[] = { - { -"RTL-8169", 0x00, 0xff7e1880,},}; - enum _DescStatusBit { OWNbit = 0x80000000, EORbit = 0x40000000, @@ -257,6 +280,8 @@ LSbit = 0x10000000, }; +#define RsvdMask 0x3fffc000 + struct TxDesc { u32 status; u32 vlan_tag; @@ -277,28 +302,33 @@ struct net_device_stats stats; /* statistics of net device */ spinlock_t lock; /* spin lock flag */ int chipset; - unsigned long cur_rx; /* Index into the Rx descriptor buffer of next Rx pkt. */ - unsigned long cur_tx; /* Index into the Tx descriptor buffer of next Rx pkt. */ - unsigned long dirty_tx; - unsigned char *TxDescArrays; /* Index of Tx Descriptor buffer */ - unsigned char *RxDescArrays; /* Index of Rx Descriptor buffer */ + int mac_version; + int phy_version; + u32 cur_rx; /* Index into the Rx descriptor buffer of next Rx pkt. */ + u32 cur_tx; /* Index into the Tx descriptor buffer of next Rx pkt. */ + u32 dirty_rx; + u32 dirty_tx; struct TxDesc *TxDescArray; /* Index of 256-alignment Tx Descriptor buffer */ struct RxDesc *RxDescArray; /* Index of 256-alignment Rx Descriptor buffer */ - unsigned char *RxBufferRings; /* Index of Rx Buffer */ - unsigned char *RxBufferRing[NUM_RX_DESC]; /* Index of Rx Buffer array */ + dma_addr_t TxPhyAddr; + dma_addr_t RxPhyAddr; + struct sk_buff *Rx_skbuff[NUM_RX_DESC]; /* Rx data buffers */ struct sk_buff *Tx_skbuff[NUM_TX_DESC]; /* Index of Transmit data buffer */ + struct timer_list timer; + unsigned long phy_link_down_cnt; }; MODULE_AUTHOR("Realtek"); MODULE_DESCRIPTION("RealTek RTL-8169 Gigabit Ethernet driver"); MODULE_PARM(media, "1-" __MODULE_STRING(MAX_UNITS) "i"); +MODULE_PARM(rx_copybreak, "i"); MODULE_LICENSE("GPL"); static int rtl8169_open(struct net_device *dev); static int rtl8169_start_xmit(struct sk_buff *skb, struct net_device *dev); static irqreturn_t rtl8169_interrupt(int irq, void *dev_instance, struct pt_regs *regs); -static void rtl8169_init_ring(struct net_device *dev); +static int rtl8169_init_ring(struct net_device *dev); static void rtl8169_hw_start(struct net_device *dev); static int rtl8169_close(struct net_device *dev); static void rtl8169_set_rx_mode(struct net_device *dev); @@ -306,11 +336,15 @@ static struct net_device_stats *rtl8169_get_stats(struct net_device *netdev); static const u16 rtl8169_intr_mask = - SYSErr | PCSTimeout | RxUnderrun | RxOverflow | RxFIFOOver | TxErr | TxOK | - RxErr | RxOK; + RxUnderrun | RxOverflow | RxFIFOOver | TxErr | TxOK | RxErr | RxOK; static const unsigned int rtl8169_rx_config = (RX_FIFO_THRESH << RxCfgFIFOShift) | (RX_DMA_BURST << RxCfgDMAShift); +#define PHY_Cap_10_Half_Or_Less PHY_Cap_10_Half +#define PHY_Cap_10_Full_Or_Less PHY_Cap_10_Full | PHY_Cap_10_Half_Or_Less +#define PHY_Cap_100_Half_Or_Less PHY_Cap_100_Half | PHY_Cap_10_Full_Or_Less +#define PHY_Cap_100_Full_Or_Less PHY_Cap_100_Full | PHY_Cap_100_Half_Or_Less + void mdio_write(void *ioaddr, int RegAddr, int value) { @@ -342,13 +376,258 @@ if (RTL_R32(PHYAR) & 0x80000000) { value = (int) (RTL_R32(PHYAR) & 0xFFFF); break; - } else { - udelay(100); } + udelay(100); } return value; } +static void rtl8169_write_gmii_reg_bit(void *ioaddr, int reg, int bitnum, + int bitval) +{ + int val; + + val = mdio_read(ioaddr, reg); + val = (bitval == 1) ? + val | (bitval << bitnum) : val & ~(0x0001 << bitnum); + mdio_write(ioaddr, reg, val & 0xffff); +} + +static void rtl8169_get_mac_version(struct rtl8169_private *tp, void *ioaddr) +{ + const struct { + u32 mask; + int mac_version; + } mac_info[] = { + { 0x1 << 26, RTL_GIGA_MAC_VER_E }, + { 0x1 << 23, RTL_GIGA_MAC_VER_D }, + { 0x00000000, RTL_GIGA_MAC_VER_B } /* Catch-all */ + }, *p = mac_info; + u32 reg; + + reg = RTL_R32(TxConfig) & 0x7c800000; + while ((reg & p->mask) != p->mask) + p++; + tp->mac_version = p->mac_version; +} + +static void rtl8169_print_mac_version(struct rtl8169_private *tp) +{ + struct { + int version; + char *msg; + } mac_print[] = { + { RTL_GIGA_MAC_VER_E, "RTL_GIGA_MAC_VER_E" }, + { RTL_GIGA_MAC_VER_D, "RTL_GIGA_MAC_VER_D" }, + { RTL_GIGA_MAC_VER_B, "RTL_GIGA_MAC_VER_B" }, + { 0, NULL } + }, *p; + + for (p = mac_print; p->msg; p++) { + if (tp->mac_version == p->version) { + dprintk("mac_version == %s (%04d)\n", p->msg, + p->version); + return; + } + } + dprintk("mac_version == Unknown\n"); +} + +static void rtl8169_get_phy_version(struct rtl8169_private *tp, void *ioaddr) +{ + const struct { + u16 mask; + u16 set; + int phy_version; + } phy_info[] = { + { 0x000f, 0x0002, RTL_GIGA_PHY_VER_G }, + { 0x000f, 0x0001, RTL_GIGA_PHY_VER_F }, + { 0x000f, 0x0000, RTL_GIGA_PHY_VER_E }, + { 0x0000, 0x0000, RTL_GIGA_PHY_VER_D } /* Catch-all */ + }, *p = phy_info; + u16 reg; + + reg = mdio_read(ioaddr, 3) & 0xffff; + while ((reg & p->mask) != p->set) + p++; + tp->phy_version = p->phy_version; +} + +static void rtl8169_print_phy_version(struct rtl8169_private *tp) +{ + struct { + int version; + char *msg; + u32 reg; + } phy_print[] = { + { RTL_GIGA_PHY_VER_G, "RTL_GIGA_PHY_VER_G", 0x0002 }, + { RTL_GIGA_PHY_VER_F, "RTL_GIGA_PHY_VER_F", 0x0001 }, + { RTL_GIGA_PHY_VER_E, "RTL_GIGA_PHY_VER_E", 0x0000 }, + { RTL_GIGA_PHY_VER_D, "RTL_GIGA_PHY_VER_D", 0x0000 }, + { 0, NULL, 0x0000 } + }, *p; + + for (p = phy_print; p->msg; p++) { + if (tp->phy_version == p->version) { + dprintk("phy_version == %s (%04x)\n", p->msg, p->reg); + return; + } + } + dprintk("phy_version == Unknown\n"); +} + +static void rtl8169_hw_phy_config(struct net_device *dev) +{ + struct rtl8169_private *tp = dev->priv; + void *ioaddr = tp->mmio_addr; + struct { + u16 regs[5]; /* Beware of bit-sign propagation */ + } phy_magic[5] = { { + { 0x0000, //w 4 15 12 0 + 0x00a1, //w 3 15 0 00a1 + 0x0008, //w 2 15 0 0008 + 0x1020, //w 1 15 0 1020 + 0x1000 } },{ //w 0 15 0 1000 + { 0x7000, //w 4 15 12 7 + 0xff41, //w 3 15 0 ff41 + 0xde60, //w 2 15 0 de60 + 0x0140, //w 1 15 0 0140 + 0x0077 } },{ //w 0 15 0 0077 + { 0xa000, //w 4 15 12 a + 0xdf01, //w 3 15 0 df01 + 0xdf20, //w 2 15 0 df20 + 0xff95, //w 1 15 0 ff95 + 0xfa00 } },{ //w 0 15 0 fa00 + { 0xb000, //w 4 15 12 b + 0xff41, //w 3 15 0 ff41 + 0xde20, //w 2 15 0 de20 + 0x0140, //w 1 15 0 0140 + 0x00bb } },{ //w 0 15 0 00bb + { 0xf000, //w 4 15 12 f + 0xdf01, //w 3 15 0 df01 + 0xdf20, //w 2 15 0 df20 + 0xff95, //w 1 15 0 ff95 + 0xbf00 } //w 0 15 0 bf00 + } + }, *p = phy_magic; + int i; + + rtl8169_print_mac_version(tp); + rtl8169_print_phy_version(tp); + + if (tp->mac_version <= RTL_GIGA_MAC_VER_B) + return; + if (tp->phy_version >= RTL_GIGA_PHY_VER_F) + return; + + dprintk("MAC version != 0 && PHY version == 0 or 1\n"); + dprintk("Do final_reg2.cfg\n"); + + /* Shazam ! */ + + // phy config for RTL8169s mac_version C chip + mdio_write(ioaddr, 31, 0x0001); //w 31 2 0 1 + mdio_write(ioaddr, 21, 0x1000); //w 21 15 0 1000 + mdio_write(ioaddr, 24, 0x65c7); //w 24 15 0 65c7 + rtl8169_write_gmii_reg_bit(ioaddr, 4, 11, 0); //w 4 11 11 0 + + for (i = 0; i < ARRAY_SIZE(phy_magic); i++, p++) { + int val, pos = 4; + + val = (mdio_read(ioaddr, pos) & 0x0fff) | (p->regs[0] & 0xffff); + mdio_write(ioaddr, pos, val); + while (--pos >= 0) + mdio_write(ioaddr, pos, p->regs[4 - pos] & 0xffff); + rtl8169_write_gmii_reg_bit(ioaddr, 4, 11, 1); //w 4 11 11 1 + rtl8169_write_gmii_reg_bit(ioaddr, 4, 11, 0); //w 4 11 11 0 + } + mdio_write(ioaddr, 31, 0x0000); //w 31 2 0 0 +} + +static void rtl8169_hw_phy_reset(struct net_device *dev) +{ + struct rtl8169_private *tp = dev->priv; + void *ioaddr = tp->mmio_addr; + int i, val; + + printk(KERN_WARNING PFX "%s: Reset RTL8169s PHY\n", dev->name); + + val = (mdio_read(ioaddr, 0) | 0x8000) & 0xffff; + mdio_write(ioaddr, 0, val); + + for (i = 50; i >= 0; i--) { + if (!(mdio_read(ioaddr, 0) & 0x8000)) + break; + udelay(100); /* Gross */ + } + + if (i < 0) { + printk(KERN_WARNING PFX "%s: no PHY Reset ack. Giving up.\n", + dev->name); + } +} + +static void rtl8169_phy_timer(unsigned long __opaque) +{ + struct net_device *dev = (struct net_device *)__opaque; + struct rtl8169_private *tp = dev->priv; + struct timer_list *timer = &tp->timer; + void *ioaddr = tp->mmio_addr; + + assert(tp->mac_version > RTL_GIGA_MAC_VER_B); + assert(tp->phy_version < RTL_GIGA_PHY_VER_G); + + if (RTL_R8(PHYstatus) & LinkStatus) + tp->phy_link_down_cnt = 0; + else { + tp->phy_link_down_cnt++; + if (tp->phy_link_down_cnt >= 12) { + int reg; + + // If link on 1000, perform phy reset. + reg = mdio_read(ioaddr, PHY_1000_CTRL_REG); + if (reg & PHY_Cap_1000_Full) + rtl8169_hw_phy_reset(dev); + + tp->phy_link_down_cnt = 0; + } + } + + mod_timer(timer, RTL8169_PHY_TIMEOUT); +} + +static inline void rtl8169_delete_timer(struct net_device *dev) +{ + struct rtl8169_private *tp = dev->priv; + struct timer_list *timer = &tp->timer; + + if ((tp->mac_version <= RTL_GIGA_MAC_VER_B) || + (tp->phy_version >= RTL_GIGA_PHY_VER_G)) + return; + + del_timer_sync(timer); + + tp->phy_link_down_cnt = 0; +} + +static inline void rtl8169_request_timer(struct net_device *dev) +{ + struct rtl8169_private *tp = dev->priv; + struct timer_list *timer = &tp->timer; + + if ((tp->mac_version <= RTL_GIGA_MAC_VER_B) || + (tp->phy_version >= RTL_GIGA_PHY_VER_G)) + return; + + tp->phy_link_down_cnt = 0; + + init_timer(timer); + timer->expires = jiffies + RTL8169_PHY_TIMEOUT; + timer->data = (unsigned long)(dev); + timer->function = rtl8169_phy_timer; + add_timer(timer); +} + static int __devinit rtl8169_init_board(struct pci_dev *pdev, struct net_device **dev_out, void **ioaddr_out) @@ -356,9 +635,9 @@ void *ioaddr = NULL; struct net_device *dev; struct rtl8169_private *tp; - int rc, i; unsigned long mmio_start, mmio_end, mmio_flags, mmio_len; - u32 tmp; + int rc, i, acpi_idle_state = 0, pm_cap; + assert(pdev != NULL); assert(ioaddr_out != NULL); @@ -379,8 +658,22 @@ // enable device (incl. PCI PM wakeup and hotplug setup) rc = pci_enable_device(pdev); - if (rc) + if (rc) { + printk(KERN_ERR PFX "%s: unable to enable device\n", pdev->slot_name); goto err_out; + } + + /* save power state before pci_enable_device overwrites it */ + pm_cap = pci_find_capability(pdev, PCI_CAP_ID_PM); + if (pm_cap) { + u16 pwr_command; + + pci_read_config_word(pdev, pm_cap + PCI_PM_CTRL, &pwr_command); + acpi_idle_state = pwr_command & PCI_PM_CTRL_STATE_MASK; + } else { + printk(KERN_ERR PFX "Cannot find PowerManagement capability, aborting.\n"); + goto err_out_free_res; + } mmio_start = pci_resource_start(pdev, 1); mmio_end = pci_resource_end(pdev, 1); @@ -402,8 +695,10 @@ } rc = pci_request_regions(pdev, dev->name); - if (rc) + if (rc) { + printk(KERN_ERR PFX "%s: Could not request regions.\n", pdev->slot_name); goto err_out_disable; + } // enable PCI bus-mastering pci_set_master(pdev); @@ -420,30 +715,32 @@ RTL_W8(ChipCmd, CmdReset); // Check that the chip has finished the reset. - for (i = 1000; i > 0; i--) + for (i = 1000; i > 0; i--) { if ((RTL_R8(ChipCmd) & CmdReset) == 0) break; - else - udelay(10); + udelay(10); + } - // identify chip attached to board - tmp = RTL_R32(TxConfig); - tmp = ((tmp & 0x7c000000) + ((tmp & 0x00800000) << 2)) >> 24; - - for (i = ARRAY_SIZE(rtl_chip_info) - 1; i >= 0; i--) - if (tmp == rtl_chip_info[i].version) { - tp->chipset = i; - goto match; - } - //if unknown chip, assume array element #0, original RTL-8169 in this case - printk(KERN_DEBUG PFX - "PCI device %s: unknown chip version, assuming RTL-8169\n", - pci_name(pdev)); - printk(KERN_DEBUG PFX "PCI device %s: TxConfig = 0x%lx\n", - pci_name(pdev), (unsigned long) RTL_R32(TxConfig)); - tp->chipset = 0; + // Identify chip attached to board + rtl8169_get_mac_version(tp, ioaddr); + rtl8169_get_phy_version(tp, ioaddr); + + rtl8169_print_mac_version(tp); + rtl8169_print_phy_version(tp); + + for (i = ARRAY_SIZE(rtl_chip_info) - 1; i >= 0; i--) { + if (tp->mac_version == rtl_chip_info[i].mac_version) + break; + } + if (i < 0) { + /* Unknown chip: assume array element #0, original RTL-8169 */ + printk(KERN_DEBUG PFX + "PCI device %s: unknown chip version, assuming %s\n", + pci_name(pdev), rtl_chip_info[0].name); + i++; + } + tp->chipset = i; -match: *ioaddr_out = ioaddr; *dev_out = dev; return 0; @@ -499,7 +796,7 @@ dev->stop = rtl8169_close; dev->tx_timeout = rtl8169_tx_timeout; dev->set_multicast_list = rtl8169_set_rx_mode; - dev->watchdog_timeo = TX_TIMEOUT; + dev->watchdog_timeo = RTL8169_TX_TIMEOUT; dev->irq = pdev->irq; dev->base_addr = (unsigned long) ioaddr; // dev->do_ioctl = mii_ioctl; @@ -528,12 +825,29 @@ "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x, " "IRQ %d\n", dev->name, - board_info[ent->driver_data].name, + rtl_chip_info[ent->driver_data].name, dev->base_addr, dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2], dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5], dev->irq); + rtl8169_hw_phy_config(dev); + + dprintk("Set MAC Reg C+CR Offset 0x82h = 0x01h\n"); + RTL_W8(0x82, 0x01); + + if (tp->mac_version < RTL_GIGA_MAC_VER_E) { + dprintk("Set PCI Latency=0x40\n"); + pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0x40); + } + + if (tp->mac_version == RTL_GIGA_MAC_VER_D) { + dprintk("Set MAC Reg C+CR Offset 0x82h = 0x01h\n"); + RTL_W8(0x82, 0x01); + dprintk("Set PHY Reg 0x0bh = 0x00h\n"); + mdio_write(ioaddr, 0x0b, 0x0000); //w 0x0b 15 0 0 + } + // if TBI is not endbled if (!(RTL_R8(PHYstatus) & TBI_Enable)) { int val = mdio_read(ioaddr, PHY_AUTO_NEGO_REG); @@ -546,23 +860,23 @@ Cap10_100 = 0, Cap1000 = 0; switch (option) { case _10_Half: - Cap10_100 = PHY_Cap_10_Half; + Cap10_100 = PHY_Cap_10_Half_Or_Less; Cap1000 = PHY_Cap_Null; break; case _10_Full: - Cap10_100 = PHY_Cap_10_Full; + Cap10_100 = PHY_Cap_10_Full_Or_Less; Cap1000 = PHY_Cap_Null; break; case _100_Half: - Cap10_100 = PHY_Cap_100_Half; + Cap10_100 = PHY_Cap_100_Half_Or_Less; Cap1000 = PHY_Cap_Null; break; case _100_Full: - Cap10_100 = PHY_Cap_100_Full; + Cap10_100 = PHY_Cap_100_Full_Or_Less; Cap1000 = PHY_Cap_Null; break; case _1000_Full: - Cap10_100 = PHY_Cap_Null; + Cap10_100 = PHY_Cap_100_Full_Or_Less; Cap1000 = PHY_Cap_1000_Full; break; default: @@ -576,9 +890,7 @@ // enable 10/100 Full/Half Mode, leave PHY_AUTO_NEGO_REG bit4:0 unchanged mdio_write(ioaddr, PHY_AUTO_NEGO_REG, - PHY_Cap_10_Half | PHY_Cap_10_Full | - PHY_Cap_100_Half | PHY_Cap_100_Full | (val & - 0x1F)); + PHY_Cap_100_Full_Or_Less | (val & 0x1f)); // enable 1000 Full Mode mdio_write(ioaddr, PHY_1000_CTRL_REG, @@ -647,56 +959,96 @@ pci_set_drvdata(pdev, NULL); } +#ifdef CONFIG_PM + +static int rtl8169_suspend(struct pci_dev *pdev, u32 state) +{ + struct net_device *dev = pci_get_drvdata(pdev); + struct rtl8169_private *tp = dev->priv; + void *ioaddr = tp->mmio_addr; + unsigned long flags; + + if (!netif_running(dev)) + return 0; + + netif_device_detach(dev); + netif_stop_queue(dev); + spin_lock_irqsave(&tp->lock, flags); + + /* Disable interrupts, stop Rx and Tx */ + RTL_W16(IntrMask, 0); + RTL_W8(ChipCmd, 0); + + /* Update the error counts. */ + tp->stats.rx_missed_errors += RTL_R32(RxMissed); + RTL_W32(RxMissed, 0); + spin_unlock_irqrestore(&tp->lock, flags); + + return 0; +} + +static int rtl8169_resume(struct pci_dev *pdev) +{ + struct net_device *dev = pci_get_drvdata(pdev); + + if (!netif_running(dev)) + return 0; + + netif_device_attach(dev); + rtl8169_hw_start(dev); + + return 0; +} + +#endif /* CONFIG_PM */ + static int rtl8169_open(struct net_device *dev) { struct rtl8169_private *tp = dev->priv; + struct pci_dev *pdev = tp->pci_dev; int retval; - u8 diff; - u32 TxPhyAddr, RxPhyAddr; retval = request_irq(dev->irq, rtl8169_interrupt, SA_SHIRQ, dev->name, dev); - if (retval) { - return retval; - } + if (retval < 0) + goto out; - tp->TxDescArrays = - kmalloc(NUM_TX_DESC * sizeof (struct TxDesc) + 256, GFP_KERNEL); - // Tx Desscriptor needs 256 bytes alignment; - TxPhyAddr = virt_to_bus(tp->TxDescArrays); - diff = 256 - (TxPhyAddr - ((TxPhyAddr >> 8) << 8)); - TxPhyAddr += diff; - tp->TxDescArray = (struct TxDesc *) (tp->TxDescArrays + diff); - - tp->RxDescArrays = - kmalloc(NUM_RX_DESC * sizeof (struct RxDesc) + 256, GFP_KERNEL); - // Rx Desscriptor needs 256 bytes alignment; - RxPhyAddr = virt_to_bus(tp->RxDescArrays); - diff = 256 - (RxPhyAddr - ((RxPhyAddr >> 8) << 8)); - RxPhyAddr += diff; - tp->RxDescArray = (struct RxDesc *) (tp->RxDescArrays + diff); + retval = -ENOMEM; - if (tp->TxDescArrays == NULL || tp->RxDescArrays == NULL) { - printk(KERN_INFO - "Allocate RxDescArray or TxDescArray failed\n"); - free_irq(dev->irq, dev); - if (tp->TxDescArrays) - kfree(tp->TxDescArrays); - if (tp->RxDescArrays) - kfree(tp->RxDescArrays); - return -ENOMEM; - } - tp->RxBufferRings = kmalloc(RX_BUF_SIZE * NUM_RX_DESC, GFP_KERNEL); - if (tp->RxBufferRings == NULL) { - printk(KERN_INFO "Allocate RxBufferRing failed\n"); - } + /* + * Rx and Tx desscriptors needs 256 bytes alignment. + * pci_alloc_consistent provides more. + */ + tp->TxDescArray = pci_alloc_consistent(pdev, R8169_TX_RING_BYTES, + &tp->TxPhyAddr); + if (!tp->TxDescArray) + goto err_free_irq; + + tp->RxDescArray = pci_alloc_consistent(pdev, R8169_RX_RING_BYTES, + &tp->RxPhyAddr); + if (!tp->RxDescArray) + goto err_free_tx; + + retval = rtl8169_init_ring(dev); + if (retval < 0) + goto err_free_rx; - rtl8169_init_ring(dev); rtl8169_hw_start(dev); - return 0; - + rtl8169_request_timer(dev); +out: + return retval; + +err_free_rx: + pci_free_consistent(pdev, R8169_RX_RING_BYTES, tp->RxDescArray, + tp->RxPhyAddr); +err_free_tx: + pci_free_consistent(pdev, R8169_TX_RING_BYTES, tp->TxDescArray, + tp->TxPhyAddr); +err_free_irq: + free_irq(dev->irq, dev); + goto out; } static void @@ -733,11 +1085,17 @@ RTL_W32(TxConfig, (TX_DMA_BURST << TxDMAShift) | (InterFrameGap << TxInterFrameGapShift)); + RTL_W16(CPlusCmd, RTL_R16(CPlusCmd)); + + if (tp->mac_version == RTL_GIGA_MAC_VER_D) { + dprintk(KERN_INFO PFX "Set MAC Reg C+CR Offset 0xE0: bit-3 and bit-14 MUST be 1\n"); + RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) | (1 << 14) | (1 << 3)); + } tp->cur_rx = 0; - RTL_W32(TxDescStartAddr, virt_to_bus(tp->TxDescArray)); - RTL_W32(RxDescStartAddr, virt_to_bus(tp->RxDescArray)); + RTL_W32(TxDescStartAddr, tp->TxPhyAddr); + RTL_W32(RxDescStartAddr, tp->RxPhyAddr); RTL_W8(Cfg9346, Cfg9346_Lock); udelay(10); @@ -755,31 +1113,131 @@ } -static void -rtl8169_init_ring(struct net_device *dev) +static inline void rtl8169_make_unusable_by_asic(struct RxDesc *desc) +{ + desc->buf_addr = 0xdeadbeef; + desc->status &= ~cpu_to_le32(OWNbit | RsvdMask); +} + +static void rtl8169_free_rx_skb(struct pci_dev *pdev, struct sk_buff **sk_buff, + struct RxDesc *desc) +{ + pci_unmap_single(pdev, le32_to_cpu(desc->buf_addr), RX_BUF_SIZE, + PCI_DMA_FROMDEVICE); + dev_kfree_skb(*sk_buff); + *sk_buff = NULL; + rtl8169_make_unusable_by_asic(desc); +} + +static inline void rtl8169_return_to_asic(struct RxDesc *desc) +{ + desc->status |= cpu_to_le32(OWNbit + RX_BUF_SIZE); +} + +static inline void rtl8169_give_to_asic(struct RxDesc *desc, dma_addr_t mapping) +{ + desc->buf_addr = cpu_to_le32(mapping); + desc->status |= cpu_to_le32(OWNbit + RX_BUF_SIZE); +} + +static int rtl8169_alloc_rx_skb(struct pci_dev *pdev, struct net_device *dev, + struct sk_buff **sk_buff, struct RxDesc *desc) +{ + struct sk_buff *skb; + dma_addr_t mapping; + int ret = 0; + + skb = dev_alloc_skb(RX_BUF_SIZE); + if (!skb) + goto err_out; + + skb->dev = dev; + skb_reserve(skb, 2); + *sk_buff = skb; + + mapping = pci_map_single(pdev, skb->tail, RX_BUF_SIZE, + PCI_DMA_FROMDEVICE); + + rtl8169_give_to_asic(desc, mapping); + +out: + return ret; + +err_out: + ret = -ENOMEM; + rtl8169_make_unusable_by_asic(desc); + goto out; +} + +static void rtl8169_rx_clear(struct rtl8169_private *tp) { - struct rtl8169_private *tp = dev->priv; int i; - tp->cur_rx = 0; - tp->cur_tx = 0; - tp->dirty_tx = 0; + for (i = 0; i < NUM_RX_DESC; i++) { + if (tp->Rx_skbuff[i]) { + rtl8169_free_rx_skb(tp->pci_dev, tp->Rx_skbuff + i, + tp->RxDescArray + i); + } + } +} + +static u32 rtl8169_rx_fill(struct rtl8169_private *tp, struct net_device *dev, + u32 start, u32 end) +{ + u32 cur; + + for (cur = start; end - cur > 0; cur++) { + int ret, i = cur % NUM_RX_DESC; + + if (tp->Rx_skbuff[i]) + continue; + + ret = rtl8169_alloc_rx_skb(tp->pci_dev, dev, tp->Rx_skbuff + i, + tp->RxDescArray + i); + if (ret < 0) + break; + } + return cur - start; +} + +static inline void rtl8169_mark_as_last_descriptor(struct RxDesc *desc) +{ + desc->status |= cpu_to_le32(EORbit); +} + +static int rtl8169_init_ring(struct net_device *dev) +{ + struct rtl8169_private *tp = dev->priv; + + tp->cur_rx = tp->dirty_rx = 0; + tp->cur_tx = tp->dirty_tx = 0; memset(tp->TxDescArray, 0x0, NUM_TX_DESC * sizeof (struct TxDesc)); memset(tp->RxDescArray, 0x0, NUM_RX_DESC * sizeof (struct RxDesc)); - for (i = 0; i < NUM_TX_DESC; i++) { - tp->Tx_skbuff[i] = NULL; - } - for (i = 0; i < NUM_RX_DESC; i++) { - if (i == (NUM_RX_DESC - 1)) - tp->RxDescArray[i].status = - (OWNbit | EORbit) + RX_BUF_SIZE; - else - tp->RxDescArray[i].status = OWNbit + RX_BUF_SIZE; + memset(tp->Tx_skbuff, 0x0, NUM_TX_DESC * sizeof(struct sk_buff *)); + memset(tp->Rx_skbuff, 0x0, NUM_RX_DESC * sizeof(struct sk_buff *)); - tp->RxBufferRing[i] = &(tp->RxBufferRings[i * RX_BUF_SIZE]); - tp->RxDescArray[i].buf_addr = virt_to_bus(tp->RxBufferRing[i]); - } + if (rtl8169_rx_fill(tp, dev, 0, NUM_RX_DESC) != NUM_RX_DESC) + goto err_out; + + rtl8169_mark_as_last_descriptor(tp->RxDescArray + NUM_RX_DESC - 1); + + return 0; + +err_out: + rtl8169_rx_clear(tp); + return -ENOMEM; +} + +static void rtl8169_unmap_tx_skb(struct pci_dev *pdev, struct sk_buff **sk_buff, + struct TxDesc *desc) +{ + u32 len = sk_buff[0]->len; + + pci_unmap_single(pdev, le32_to_cpu(desc->buf_addr), + len < ETH_ZLEN ? ETH_ZLEN : len, PCI_DMA_TODEVICE); + desc->buf_addr = 0x00; + *sk_buff = NULL; } static void @@ -789,9 +1247,12 @@ tp->cur_tx = 0; for (i = 0; i < NUM_TX_DESC; i++) { - if (tp->Tx_skbuff[i] != NULL) { - dev_kfree_skb(tp->Tx_skbuff[i]); - tp->Tx_skbuff[i] = NULL; + struct sk_buff *skb = tp->Tx_skbuff[i]; + + if (skb) { + rtl8169_unmap_tx_skb(tp->pci_dev, tp->Tx_skbuff + i, + tp->TxDescArray + i); + dev_kfree_skb(skb); tp->stats.tx_dropped++; } } @@ -829,41 +1290,51 @@ struct rtl8169_private *tp = dev->priv; void *ioaddr = tp->mmio_addr; int entry = tp->cur_tx % NUM_TX_DESC; + u32 len = skb->len; - if (skb->len < ETH_ZLEN) { + if (unlikely(skb->len < ETH_ZLEN)) { skb = skb_padto(skb, ETH_ZLEN); - if (skb == NULL) - return 0; + if (!skb) + goto err_update_stats; + len = ETH_ZLEN; } spin_lock_irq(&tp->lock); - if ((tp->TxDescArray[entry].status & OWNbit) == 0) { + if (!(le32_to_cpu(tp->TxDescArray[entry].status) & OWNbit)) { + dma_addr_t mapping; + + mapping = pci_map_single(tp->pci_dev, skb->data, len, + PCI_DMA_TODEVICE); + tp->Tx_skbuff[entry] = skb; - tp->TxDescArray[entry].buf_addr = virt_to_bus(skb->data); - if (entry != (NUM_TX_DESC - 1)) - tp->TxDescArray[entry].status = - (OWNbit | FSbit | LSbit) | ((skb->len > ETH_ZLEN) ? - skb->len : ETH_ZLEN); - else - tp->TxDescArray[entry].status = - (OWNbit | EORbit | FSbit | LSbit) | - ((skb->len > ETH_ZLEN) ? skb->len : ETH_ZLEN); + tp->TxDescArray[entry].buf_addr = cpu_to_le32(mapping); + tp->TxDescArray[entry].status = cpu_to_le32(OWNbit | FSbit | + LSbit | len | (EORbit * !((entry + 1) % NUM_TX_DESC))); + RTL_W8(TxPoll, 0x40); //set polling bit dev->trans_start = jiffies; tp->cur_tx++; - } + } else + goto err_drop; - spin_unlock_irq(&tp->lock); if ((tp->cur_tx - NUM_TX_DESC) == tp->dirty_tx) { netif_stop_queue(dev); } +out: + spin_unlock_irq(&tp->lock); return 0; + +err_drop: + dev_kfree_skb(skb); +err_update_stats: + tp->stats.tx_dropped++; + goto out; } static void @@ -881,11 +1352,17 @@ tx_left = tp->cur_tx - dirty_tx; while (tx_left > 0) { - if ((tp->TxDescArray[entry].status & OWNbit) == 0) { - dev_kfree_skb_irq(tp-> - Tx_skbuff[dirty_tx % NUM_TX_DESC]); - tp->Tx_skbuff[dirty_tx % NUM_TX_DESC] = NULL; + if (!(le32_to_cpu(tp->TxDescArray[entry].status) & OWNbit)) { + int cur = dirty_tx % NUM_TX_DESC; + struct sk_buff *skb = tp->Tx_skbuff[cur]; + + /* FIXME: is it really accurate for TxErr ? */ + tp->stats.tx_bytes += skb->len >= ETH_ZLEN ? + skb->len : ETH_ZLEN; tp->stats.tx_packets++; + rtl8169_unmap_tx_skb(tp->pci_dev, tp->Tx_skbuff + cur, + tp->TxDescArray + cur); + dev_kfree_skb_irq(skb); dirty_tx++; tx_left--; entry++; @@ -899,70 +1376,95 @@ } } +static inline int rtl8169_try_rx_copy(struct sk_buff **sk_buff, int pkt_size, + struct RxDesc *desc, + struct net_device *dev) +{ + int ret = -1; + + if (pkt_size < rx_copybreak) { + struct sk_buff *skb; + + skb = dev_alloc_skb(pkt_size + 2); + if (skb) { + skb->dev = dev; + skb_reserve(skb, 2); + eth_copy_and_sum(skb, sk_buff[0]->tail, pkt_size, 0); + *sk_buff = skb; + rtl8169_return_to_asic(desc); + ret = 0; + } + } + return ret; +} + static void rtl8169_rx_interrupt(struct net_device *dev, struct rtl8169_private *tp, void *ioaddr) { - int cur_rx; - struct sk_buff *skb; - int pkt_size = 0; + int cur_rx, delta; assert(dev != NULL); assert(tp != NULL); assert(ioaddr != NULL); - cur_rx = tp->cur_rx; + cur_rx = tp->cur_rx % NUM_RX_DESC; - while ((tp->RxDescArray[cur_rx].status & OWNbit) == 0) { + while (!(le32_to_cpu(tp->RxDescArray[cur_rx].status) & OWNbit)) { + u32 status = le32_to_cpu(tp->RxDescArray[cur_rx].status); - if (tp->RxDescArray[cur_rx].status & RxRES) { + if (status & RxRES) { printk(KERN_INFO "%s: Rx ERROR!!!\n", dev->name); tp->stats.rx_errors++; - if (tp->RxDescArray[cur_rx].status & (RxRWT | RxRUNT)) + if (status & (RxRWT | RxRUNT)) tp->stats.rx_length_errors++; - if (tp->RxDescArray[cur_rx].status & RxCRC) + if (status & RxCRC) tp->stats.rx_crc_errors++; } else { - pkt_size = - (int) (tp->RxDescArray[cur_rx]. - status & 0x00001FFF) - 4; - skb = dev_alloc_skb(pkt_size + 2); - if (skb != NULL) { - skb->dev = dev; - skb_reserve(skb, 2); // 16 byte align the IP fields. // - eth_copy_and_sum(skb, tp->RxBufferRing[cur_rx], - pkt_size, 0); - skb_put(skb, pkt_size); - skb->protocol = eth_type_trans(skb, dev); - netif_rx(skb); - - if (cur_rx == (NUM_RX_DESC - 1)) - tp->RxDescArray[cur_rx].status = - (OWNbit | EORbit) + RX_BUF_SIZE; - else - tp->RxDescArray[cur_rx].status = - OWNbit + RX_BUF_SIZE; - - tp->RxDescArray[cur_rx].buf_addr = - virt_to_bus(tp->RxBufferRing[cur_rx]); - dev->last_rx = jiffies; - tp->stats.rx_bytes += pkt_size; - tp->stats.rx_packets++; - } else { - printk(KERN_WARNING - "%s: Memory squeeze, deferring packet.\n", - dev->name); - /* We should check that some rx space is free. - If not, free one and mark stats->rx_dropped++. */ - tp->stats.rx_dropped++; + struct RxDesc *desc = tp->RxDescArray + cur_rx; + struct sk_buff *skb = tp->Rx_skbuff[cur_rx]; + int pkt_size = (status & 0x00001FFF) - 4; + + pci_dma_sync_single(tp->pci_dev, + le32_to_cpu(desc->buf_addr), + RX_BUF_SIZE, PCI_DMA_FROMDEVICE); + + if (rtl8169_try_rx_copy(&skb, pkt_size, desc, dev)) { + pci_unmap_single(tp->pci_dev, + le32_to_cpu(desc->buf_addr), + RX_BUF_SIZE, + PCI_DMA_FROMDEVICE); + tp->Rx_skbuff[cur_rx] = NULL; } - } - - cur_rx = (cur_rx + 1) % NUM_RX_DESC; - - } - tp->cur_rx = cur_rx; + skb_put(skb, pkt_size); + skb->protocol = eth_type_trans(skb, dev); + netif_rx(skb); + + dev->last_rx = jiffies; + tp->stats.rx_bytes += pkt_size; + tp->stats.rx_packets++; + } + + tp->cur_rx++; + cur_rx = tp->cur_rx % NUM_RX_DESC; + } + + delta = rtl8169_rx_fill(tp, dev, tp->dirty_rx, tp->cur_rx); + if (delta > 0) + tp->dirty_rx += delta; + else if (delta < 0) + printk(KERN_INFO "%s: no Rx buffer allocated\n", dev->name); + + /* + * FIXME: until there is periodic timer to try and refill the ring, + * a temporary shortage may definitely kill the Rx process. + * - disable the asic to try and avoid an overflow and kick it again + * after refill ? + * - how do others driver handle this condition (Uh oh...). + */ + if (tp->dirty_rx + NUM_RX_DESC == tp->cur_rx) + printk(KERN_EMERG "%s: Rx buffers exhausted\n", dev->name); } /* The interrupt handler does all of the Rx thread work and cleans up after the Tx thread. */ @@ -991,9 +1493,7 @@ RTL_W16(IntrStatus, (status & RxFIFOOver) ? (status | RxOverflow) : status); - if ((status & - (SYSErr | PCSTimeout | RxUnderrun | RxOverflow | RxFIFOOver - | TxErr | TxOK | RxErr | RxOK)) == 0) + if (!(status & rtl8169_intr_mask)) break; // Rx interrupt @@ -1023,11 +1523,13 @@ rtl8169_close(struct net_device *dev) { struct rtl8169_private *tp = dev->priv; + struct pci_dev *pdev = tp->pci_dev; void *ioaddr = tp->mmio_addr; - int i; netif_stop_queue(dev); + rtl8169_delete_timer(dev); + spin_lock_irq(&tp->lock); /* Stop the chip's Tx and Rx DMA processes. */ @@ -1046,16 +1548,15 @@ free_irq(dev->irq, dev); rtl8169_tx_clear(tp); - kfree(tp->TxDescArrays); - kfree(tp->RxDescArrays); - tp->TxDescArrays = NULL; - tp->RxDescArrays = NULL; + + rtl8169_rx_clear(tp); + + pci_free_consistent(pdev, R8169_RX_RING_BYTES, tp->RxDescArray, + tp->RxPhyAddr); + pci_free_consistent(pdev, R8169_TX_RING_BYTES, tp->TxDescArray, + tp->TxPhyAddr); tp->TxDescArray = NULL; tp->RxDescArray = NULL; - kfree(tp->RxBufferRings); - for (i = 0; i < NUM_RX_DESC; i++) { - tp->RxBufferRing[i] = NULL; - } return 0; } @@ -1109,11 +1610,26 @@ spin_unlock_irqrestore(&tp->lock, flags); } +/** + * rtl8169_get_stats - Get rtl8169 read/write statistics + * @dev: The Ethernet Device to get statistics for + * + * Get TX/RX statistics for rtl8169 + */ struct net_device_stats * rtl8169_get_stats(struct net_device *dev) { struct rtl8169_private *tp = dev->priv; + void *ioaddr = tp->mmio_addr; + unsigned long flags; + if (netif_running(dev)) { + spin_lock_irqsave(&tp->lock, flags); + tp->stats.rx_missed_errors += RTL_R32(RxMissed); + RTL_W32(RxMissed, 0); + spin_unlock_irqrestore(&tp->lock, flags); + } + return &tp->stats; } @@ -1122,8 +1638,10 @@ .id_table = rtl8169_pci_tbl, .probe = rtl8169_init_one, .remove = __devexit_p(rtl8169_remove_one), - .suspend = NULL, - .resume = NULL, +#ifdef CONFIG_PM + .suspend = rtl8169_suspend, + .resume = rtl8169_resume, +#endif }; static int __init diff -Nru a/drivers/net/saa9730.c b/drivers/net/saa9730.c --- a/drivers/net/saa9730.c Thu Jan 22 18:59:25 2004 +++ b/drivers/net/saa9730.c Thu Jan 22 18:59:25 2004 @@ -996,11 +996,11 @@ struct net_device *dev = pci_get_drvdata(pdev); if (dev) { - + unregister_netdev(dev); + if (dev->priv) kfree(dev->priv); - unregister_netdev(dev); free_netdev(dev); pci_release_regions(pdev); pci_disable_device(pdev); @@ -1015,17 +1015,10 @@ unsigned char ethernet_addr[6]; int ret = 0; - dev = init_etherdev(dev, 0); - - if (!dev) - return -ENOMEM; - dev->open = lan_saa9730_open_fail; - if (get_ethernet_addr(ethernet_addr)) { - ret = -ENODEV; - goto out; - } + if (get_ethernet_addr(ethernet_addr)) + return -ENODEV; memcpy(dev->dev_addr, ethernet_addr, 6); dev->base_addr = ioaddr; @@ -1035,15 +1028,16 @@ * Make certain the data structures used by the controller are aligned * and DMAble. */ + /* + * XXX: that is obviously broken - kfree() won't be happy with us. + */ lp = (struct lan_saa9730_private *) (((unsigned long) kmalloc(sizeof(*lp) + 7, GFP_DMA | GFP_KERNEL) + 7) & ~7); - if (!lp) { - ret = -ENOMEM; - goto out; - } + if (!lp) + return -ENOMEM; dev->priv = lp; memset(lp, 0, sizeof(*lp)); @@ -1057,6 +1051,7 @@ SAA9730_EVM_REGS_ADDR); /* Allocate LAN RX/TX frame buffer space. */ + /* FIXME: a leak */ if ((ret = lan_saa9730_allocate_buffers(lp))) goto out; @@ -1095,63 +1090,69 @@ dev->watchdog_timeo = (HZ >> 1); dev->dma = 0; + ret = register_netdev(dev); + if (ret) + goto out; return 0; out: - if (dev) { - if (dev->priv) - kfree(dev->priv); - unregister_netdevice(dev); - free_netdev(dev); - } - + if (dev->priv) + kfree(dev->priv); return ret; } static int __devinit saa9730_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) { - struct net_device *dev = NULL; + struct net_device *dev; unsigned int pci_ioaddr; int err; if (lan_saa9730_debug > 1) printk("saa9730.c: PCI bios is present, checking for devices...\n"); + err = -ENOMEM; + dev = alloc_etherdev(0); + if (!dev) + goto out; + + SET_MODULE_OWNER(dev); + err = pci_enable_device(pdev); if (err) { printk(KERN_ERR "Cannot enable PCI device, aborting.\n"); - goto out; + goto out1; } err = pci_request_regions(pdev, DRV_MODULE_NAME); if (err) { printk(KERN_ERR "Cannot obtain PCI resources, aborting.\n"); - goto out_disable_pdev; + goto out2; } pci_irq_line = pdev->irq; /* LAN base address in located at BAR 1. */ - + pci_ioaddr = pci_resource_start(pdev, 1); pci_set_master(pdev); - + printk("Found SAA9730 (PCI) at %#x, irq %d.\n", pci_ioaddr, pci_irq_line); err = lan_saa9730_init(dev, pci_ioaddr, pci_irq_line); if (err) { printk("Lan init failed"); - goto out_disable_pdev; + goto out2; } - + pci_set_drvdata(pdev, dev); return 0; - out_disable_pdev: +out2: pci_disable_device(pdev); - out: - pci_set_drvdata(pdev, NULL); +out1: + free_netdev(dev); +out: return err; } diff -Nru a/drivers/net/sb1250-mac.c b/drivers/net/sb1250-mac.c --- a/drivers/net/sb1250-mac.c Thu Jan 22 18:59:26 2004 +++ b/drivers/net/sb1250-mac.c Thu Jan 22 18:59:26 2004 @@ -2372,6 +2372,7 @@ unsigned char *eaddr; uint64_t ea_reg; int i; + int err; sc = (struct sbmac_softc *)dev->priv; @@ -2430,7 +2431,6 @@ spin_lock_init(&(sc->sbm_lock)); - ether_setup(dev); dev->open = sbmac_open; dev->hard_start_xmit = sbmac_start_tx; dev->stop = sbmac_close; @@ -2444,8 +2444,11 @@ /* This is needed for PASS2 for Rx H/W checksum feature */ sbmac_set_iphdr_offset(sc); - - return 0; + + err = register_netdev(dev); + if (err) + sbmac_uninitctx(sc); + return err; } @@ -2811,13 +2814,12 @@ } #endif -static struct net_device *dev_sbmac[MAX_UNITS] = {0,0,0}; +static struct net_device *dev_sbmac[MAX_UNITS]; static int __init sbmac_init_module(void) { int idx; - int macidx = 0; struct net_device *dev; sbmac_port_t port; int chip_max_units; @@ -2884,26 +2886,24 @@ * Okay, cool. Initialize this MAC. */ - dev = init_etherdev(NULL,sizeof(struct sbmac_softc)); + dev = alloc_etherdev(sizeof(struct sbmac_softc)); if (!dev) - return -ENOMEM; /* return ENOMEM */ + return -ENOMEM; /* return ENOMEM */ printk(KERN_DEBUG "sbmac: configuring MAC at %lx\n", port); dev->irq = K_INT_MAC_0 + idx; dev->base_addr = port; dev->mem_end = 0; - /*dev->init = sbmac_init;*/ - sbmac_init(dev, macidx); - - dev_sbmac[macidx] = dev; - macidx++; + if (sbmac_init(dev, idx)) { + port = A_MAC_CHANNEL_BASE(idx); + SBMAC_WRITECSR(KSEG1ADDR(port+R_MAC_ETHERNET_ADDR), + sbmac_orig_hwaddr[idx] ); + free_netdev(dev); + continue; + } + dev_sbmac[idx++] = dev; } - - /* - * Should we care, 'macidx' is the total number of enabled MACs. - */ - return 0; } @@ -2916,21 +2916,12 @@ sbmac_port_t port; for (idx = 0; idx < MAX_UNITS; idx++) { dev = dev_sbmac[idx]; - if (dev == NULL) - continue; - if (dev->priv != NULL) { - struct sbmac_softc *sc = (struct sbmac_softc *) dev->priv; - + if (!dev) { + struct sbmac_softc *sc = dev->priv; unregister_netdev(dev); - sbmac_uninitctx(sc); - + free_netdev(dev); } - - port = A_MAC_CHANNEL_BASE(idx); - SBMAC_WRITECSR(KSEG1ADDR(port+R_MAC_ETHERNET_ADDR), sbmac_orig_hwaddr[idx] ); - free_netdev(dev); - dev_sbmac[idx] = NULL; } } diff -Nru a/drivers/net/seeq8005.c b/drivers/net/seeq8005.c --- a/drivers/net/seeq8005.c Thu Jan 22 18:59:26 2004 +++ b/drivers/net/seeq8005.c Thu Jan 22 18:59:26 2004 @@ -78,8 +78,6 @@ /* Index to functions, as function prototypes. */ -extern int seeq8005_probe(struct net_device *dev); - static int seeq8005_probe1(struct net_device *dev, int ioaddr); static int seeq8005_open(struct net_device *dev); static void seeq8005_timeout(struct net_device *dev); @@ -102,22 +100,48 @@ If dev->base_addr == 1, always return failure. */ -int __init -seeq8005_probe(struct net_device *dev) -{ - int i; - int base_addr = dev ? dev->base_addr : 0; - - if (base_addr > 0x1ff) /* Check a single specified location. */ - return seeq8005_probe1(dev, base_addr); - else if (base_addr != 0) /* Don't probe at all. */ - return -ENXIO; - - for (i = 0; seeq8005_portlist[i]; i++) - if (seeq8005_probe1(dev, seeq8005_portlist[i]) == 0) - return 0; +static int io = 0x320; +static int irq = 10; - return -ENODEV; +struct net_device * __init seeq8005_probe(int unit) +{ + struct net_device *dev = alloc_etherdev(sizeof(struct net_local)); + unsigned *port; + int err = 0; + + if (!dev) + return ERR_PTR(-ENODEV); + + if (unit >= 0) { + sprintf(dev->name, "eth%d", unit); + netdev_boot_setup_check(dev); + io = dev->base_addr; + irq = dev->irq; + } + + if (io > 0x1ff) { /* Check a single specified location. */ + err = seeq8005_probe1(dev, io); + } else if (io != 0) { /* Don't probe at all. */ + err = -ENXIO; + } else { + for (port = seeq8005_portlist; *port; port++) { + if (seeq8005_probe1(dev, *port) == 0) + break; + } + if (!*port) + err = -ENODEV; + } + if (err) + goto out; + err = register_netdev(dev); + if (err) + goto out1; + return dev; +out1: + release_region(dev->base_addr, SEEQ8005_IO_EXTENT); +out: + free_netdev(dev); + return ERR_PTR(err); } /* This is the real probe routine. Linux has a history of friendly device @@ -274,6 +298,7 @@ /* Fill in the 'dev' fields. */ dev->base_addr = ioaddr; + dev->irq = irq; /* Retrieve and print the ethernet address. */ for (i = 0; i < 6; i++) @@ -307,13 +332,6 @@ } } #endif - - /* Initialize the device structure. */ - dev->priv = kmalloc(sizeof(struct net_local), GFP_KERNEL); - if (dev->priv == NULL) - return -ENOMEM; - memset(dev->priv, 0, sizeof(struct net_local)); - dev->open = seeq8005_open; dev->stop = seeq8005_close; dev->hard_start_xmit = seeq8005_send_packet; @@ -321,10 +339,6 @@ dev->watchdog_timeo = HZ/20; dev->get_stats = seeq8005_get_stats; dev->set_multicast_list = set_multicast_list; - - /* Fill in the fields of the device structure with ethernet values. */ - ether_setup(dev); - dev->flags &= ~IFF_MULTICAST; return 0; @@ -721,9 +735,7 @@ #ifdef MODULE -static struct net_device dev_seeq = { .init = seeq8005_probe }; -static int io = 0x320; -static int irq = 10; +static struct net_device *dev_seeq; MODULE_LICENSE("GPL"); MODULE_PARM(io, "i"); MODULE_PARM(irq, "i"); @@ -732,28 +744,17 @@ int init_module(void) { - dev_seeq.irq=irq; - dev_seeq.base_addr=io; - if (register_netdev(&dev_seeq) != 0) - return -EIO; + dev_seeq = seeq8005_probe(-1); + if (IS_ERR(dev_seeq)) + return PTR_ERR(dev_seeq); return 0; } void cleanup_module(void) { - unregister_netdev(&dev_seeq); - - /* - * Free up the private structure, or leak memory :-) - */ - - kfree(dev_seeq.priv); - dev_seeq.priv = NULL; /* gets re-allocated by el1_probe1 */ - - /* - * If we don't do this, we can't re-insmod it later. - */ - release_region(dev_seeq.base_addr, SEEQ8005_IO_EXTENT); + unregister_netdev(dev_seeq); + release_region(dev_seeq->base_addr, SEEQ8005_IO_EXTENT); + free_netdev(dev_seeq); } #endif /* MODULE */ diff -Nru a/drivers/net/sgiseeq.c b/drivers/net/sgiseeq.c --- a/drivers/net/sgiseeq.c Thu Jan 22 18:59:26 2004 +++ b/drivers/net/sgiseeq.c Thu Jan 22 18:59:26 2004 @@ -600,6 +600,7 @@ { struct net_device *dev; struct sgiseeq_private *sp; + int err = -ENOMEM; int i; sp = (struct sgiseeq_private *) get_zeroed_page(GFP_KERNEL); @@ -609,19 +610,17 @@ return -ENOMEM; } - dev = init_etherdev(NULL, 0); + dev = alloc_etherdev(0); if (!dev) { printk (KERN_ERR "Seeq8003: Could not allocate memory for device.\n"); - free_page((unsigned long) sp); - return -ENOMEM; + goto out; } if (request_irq(irq, sgiseeq_interrupt, 0, sgiseeqstr, dev)) { - printk(KERN_ERR "Seeq8003: Can't get irq %d\n", dev->irq); - free_page((unsigned long) sp); - unregister_netdev(dev); - return -EAGAIN; + printk(KERN_ERR "Seeq8003: Can't get irq %d\n", irq); + err = -EAGAIN; + goto out1; } printk(KERN_INFO "%s: SGI Seeq8003 ", dev->name); @@ -637,6 +636,8 @@ } printk("\n"); + SET_MODULE_OWNER(dev); + dev->priv = sp; #ifdef DEBUG gpriv = sp; @@ -677,12 +678,22 @@ dev->set_multicast_list = sgiseeq_set_multicast; dev->irq = irq; dev->dma = 0; - ether_setup(dev); + + err = register_netdev(dev); + if (err) + goto out2; sp->next_module = root_sgiseeq_dev; root_sgiseeq_dev = dev; return 0; +out2: + free_irq(dev->irq, dev); +out1: + free_netdev(dev); +out: + free_page((unsigned long) sp); + return err; } static int __init sgiseeq_probe(void) @@ -701,9 +712,9 @@ while (dev) { sp = (struct sgiseeq_private *) dev->priv; next = sp->next_module; + unregister_netdev(dev); free_irq(dev->irq, dev); free_page((unsigned long) sp); - unregister_netdev(dev); free_netdev(dev); dev = next; } diff -Nru a/drivers/net/shaper.c b/drivers/net/shaper.c --- a/drivers/net/shaper.c Thu Jan 22 18:59:26 2004 +++ b/drivers/net/shaper.c Thu Jan 22 18:59:26 2004 @@ -642,7 +642,6 @@ dev->open = shaper_open; dev->stop = shaper_close; - dev->destructor = free_netdev; dev->hard_start_xmit = shaper_start_xmit; dev->get_stats = shaper_get_stats; dev->set_multicast_list = NULL; @@ -718,8 +717,10 @@ if (!dev) break; - if (register_netdev(dev)) + if (register_netdev(dev)) { + free_netdev(dev); break; + } devs[i] = dev; shapers_registered++; @@ -737,9 +738,12 @@ { int i; - for (i = 0; i < shapers_registered; i++) - if (devs[i]) + for (i = 0; i < shapers_registered; i++) { + if (devs[i]) { unregister_netdev(devs[i]); + free_netdev(devs[i]); + } + } kfree(devs); devs = NULL; diff -Nru a/drivers/net/sk98lin/skge.c b/drivers/net/sk98lin/skge.c --- a/drivers/net/sk98lin/skge.c Thu Jan 22 18:59:23 2004 +++ b/drivers/net/sk98lin/skge.c Thu Jan 22 18:59:23 2004 @@ -1253,7 +1253,7 @@ if ((pAC->GIni.GIMacsFound == 2) && pAC->RlmtNets == 2){ unregister_netdev(pAC->dev[1]); - kfree(pAC->dev[1]); + free_netdev(pAC->dev[1]); } FreeResources(SkGeRootDev); diff -Nru a/drivers/net/sk_g16.c b/drivers/net/sk_g16.c --- a/drivers/net/sk_g16.c Thu Jan 22 18:59:27 2004 +++ b/drivers/net/sk_g16.c Thu Jan 22 18:59:27 2004 @@ -457,8 +457,6 @@ /* static variables */ static SK_RAM *board; /* pointer to our memory mapped board components */ -static struct net_device *SK_dev; -unsigned long SK_ioaddr; static spinlock_t SK_lock = SPIN_LOCK_UNLOCKED; /* Macros */ @@ -472,7 +470,6 @@ * See for short explanation of each function its definitions header. */ -int SK_init(struct net_device *dev); static int SK_probe(struct net_device *dev, short ioaddr); static void SK_timeout(struct net_device *dev); @@ -530,84 +527,71 @@ * YY/MM/DD uid Description -*/ +static int io; /* 0 == probe */ + /* * Check for a network adaptor of this type, and return '0' if one exists. * If dev->base_addr == 0, probe all likely locations. * If dev->base_addr == 1, always return failure. */ -int __init SK_init(struct net_device *dev) +struct net_device * __init SK_init(int unit) { - int ioaddr; /* I/O port address used for POS regs */ int *port, ports[] = SK_IO_PORTS; /* SK_G16 supported ports */ static unsigned version_printed; + struct net_device *dev = alloc_etherdev(sizeof(struct priv)); + int err = -ENODEV; - /* get preconfigured base_addr from dev which is done in Space.c */ - int base_addr = dev->base_addr; + if (!dev) + return ERR_PTR(-ENOMEM); + + if (unit >= 0) { + sprintf(dev->name, "eth%d", unit); + netdev_boot_setup_check(dev); + io = dev->base_addr; + } if (version_printed++ == 0) PRINTK(("%s: %s", SK_NAME, rcsid)); - if (base_addr > 0x0ff) /* Check a single specified address */ - { - int rc = -ENODEV; - - ioaddr = base_addr; + if (io > 0xff) { /* Check a single specified address */ + err = -EBUSY; + /* Check if on specified address is a SK_G16 */ + if (request_region(io, ETHERCARD_TOTAL_SIZE, "sk_g16")) { + err = SK_probe(dev, io); + if (!err) + goto got_it; + release_region(io, ETHERCARD_TOTAL_SIZE); + } + } else if (io > 0) { /* Don't probe at all */ + err = -ENXIO; + } else { + /* Autoprobe base_addr */ + for (port = &ports[0]; *port; port++) { + io = *port; + + /* Check if I/O Port region is used by another board */ + if (!request_region(io, ETHERCARD_TOTAL_SIZE, "sk_g16")) + continue; /* Try next Port address */ + + /* Check if at ioaddr is a SK_G16 */ + if (SK_probe(dev, io) == 0) + goto got_it; - /* Check if on specified address is a SK_G16 */ - if (!request_region(ioaddr, ETHERCARD_TOTAL_SIZE, "sk_g16")) - return -EBUSY; - - if ( (inb(SK_POS0) == SK_IDLOW) || - (inb(SK_POS1) == SK_IDHIGH) ) - { - rc = SK_probe(dev, ioaddr); - } - - if (rc) - release_region(ioaddr, ETHERCARD_TOTAL_SIZE); - return rc; - } - else if (base_addr > 0) /* Don't probe at all */ - { - return -ENXIO; + release_region(io, ETHERCARD_TOTAL_SIZE); + } } - - /* Autoprobe base_addr */ - - for (port = &ports[0]; *port; port++) - { - ioaddr = *port; /* we need ioaddr for accessing POS regs */ - - /* Check if I/O Port region is used by another board */ - - if (!request_region(ioaddr, ETHERCARD_TOTAL_SIZE, "sk_g16")) - { - continue; /* Try next Port address */ - } - - /* Check if at ioaddr is a SK_G16 */ - - if ( !(inb(SK_POS0) == SK_IDLOW) || - !(inb(SK_POS1) == SK_IDHIGH) ) - { - release_region(ioaddr, ETHERCARD_TOTAL_SIZE); - continue; /* Try next Port address */ - } - - dev->base_addr = ioaddr; /* Set I/O Port Address */ - - if (SK_probe(dev, ioaddr) == 0) - { - return 0; /* Card found and initialized */ - } - - release_region(ioaddr, ETHERCARD_TOTAL_SIZE); +err_out: + free_netdev(dev); + return ERR_PTR(err); + +got_it: + err = register_netdev(dev); + if (err) { + release_region(dev->base_addr, ETHERCARD_TOTAL_SIZE); + goto err_out; } - - dev->base_addr = base_addr; /* Write back original base_addr */ - - return -ENODEV; /* Failed to find or init driver */ + return dev; } /* End of SK_init */ @@ -620,54 +604,25 @@ #ifdef MODULE -static int io; /* 0 == probe */ + +static struct net_device *SK_dev; static int __init SK_init_module (void) { - int rc; - - SK_dev = init_etherdev (NULL, 0); - if (!SK_dev) - return -ENOMEM; - - SK_dev->base_addr = io; - - rc = SK_init (SK_dev); - if (rc) { - unregister_netdev (SK_dev); - kfree (SK_dev); - SK_dev = NULL; - } - - return rc; + SK_dev = SK_init(-1); + return IS_ERR(SK_dev) ? PTR_ERR(SK_dev) : 0; } -#endif /* MODULE */ - static void __exit SK_cleanup_module (void) { - if (SK_dev) { - if (SK_dev->priv) { - kfree(SK_dev->priv); - SK_dev->priv = NULL; - } - unregister_netdev(SK_dev); - free_netdev(SK_dev); - SK_dev = NULL; - } - if (SK_ioaddr) { - release_region(SK_ioaddr, ETHERCARD_TOTAL_SIZE); - SK_ioaddr = 0; - } - + unregister_netdev(SK_dev); + release_region(SK_dev->base_addr, ETHERCARD_TOTAL_SIZE); + free_netdev(SK_dev); } - -#ifdef MODULE module_init(SK_init_module); -#endif module_exit(SK_cleanup_module); - +#endif /*- @@ -695,7 +650,11 @@ int sk_addr_flag = 0; /* SK ADDR correct? 1 - no, 0 - yes */ unsigned int rom_addr; /* used to store RAM address used for POS_ADDR */ - struct priv *p; /* SK_G16 private structure */ + struct priv *p = dev->priv; /* SK_G16 private structure */ + + if (inb(SK_POS0) != SK_IDLOW || inb(SK_POS1) != SK_IDHIGH) + return -ENODEV; + dev->base_addr = ioaddr; if (SK_ADDR & 0x3fff || SK_ADDR < 0xa0000) { @@ -837,12 +796,6 @@ dev->dev_addr[4], dev->dev_addr[5]); - /* Allocate memory for private structure */ - p = dev->priv = (void *) kmalloc(sizeof(struct priv), GFP_KERNEL); - if (p == NULL) { - printk("%s: ERROR - no memory for driver data!\n", dev->name); - return -ENOMEM; - } memset((char *) dev->priv, 0, sizeof(struct priv)); /* clear memory */ /* Assign our Device Driver functions */ @@ -856,10 +809,6 @@ dev->watchdog_timeo = HZ/7; - /* Set the generic fields of the device structure */ - - ether_setup(dev); - dev->flags &= ~IFF_MULTICAST; /* Initialize private structure */ @@ -884,12 +833,7 @@ SK_print_pos(dev, "End of SK_probe"); SK_print_ram(dev); #endif - - SK_dev = dev; - SK_ioaddr = ioaddr; - return 0; /* Initialization done */ - } /* End of SK_probe() */ @@ -1280,7 +1224,7 @@ memcpy_toio((tmdp->u.buffer & 0x00ffffff), skb->data, skb->len); if (len != skb->len) - memcpy_toio((tmdp->u.buffer & 0x00ffffff) + sb->len, pad, len-skb->len); + memcpy_toio((tmdp->u.buffer & 0x00ffffff) + skb->len, pad, len-skb->len); writew(-len, &tmdp->blen); /* set length to transmit */ diff -Nru a/drivers/net/sk_mca.c b/drivers/net/sk_mca.c --- a/drivers/net/sk_mca.c Thu Jan 22 18:59:26 2004 +++ b/drivers/net/sk_mca.c Thu Jan 22 18:59:26 2004 @@ -1022,18 +1022,39 @@ static int startslot; /* counts through slots when probing multiple devices */ -int __init skmca_probe(struct net_device *dev) +static void cleanup_card(struct net_device *dev) { + skmca_priv *priv = dev->priv; + DeinitBoard(dev); + if (dev->irq != 0) + free_irq(dev->irq, dev); + mca_mark_as_unused(priv->slot); + mca_set_adapter_procfn(priv->slot, NULL, NULL); +} + +struct net_device * __init skmca_probe(int unit) +{ + struct net_device *dev; int force_detect = 0; int junior, slot, i; int base = 0, irq = 0; skmca_priv *priv; skmca_medium medium; + int err; /* can't work without an MCA bus ;-) */ if (MCA_bus == 0) - return -ENODEV; + return ERR_PTR(-ENODEV); + + dev = alloc_etherdev(sizeof(skmca_priv)); + if (!dev) + return ERR_PTR(-ENOMEM); + + if (unit >= 0) { + sprintf(dev->name, "eth%d", unit); + netdev_boot_setup_check(dev); + } SET_MODULE_OWNER(dev); @@ -1044,37 +1065,24 @@ /* search through slots */ - if (dev != NULL) { - base = dev->mem_start; - irq = dev->irq; - } - slot = dofind(&junior, startslot); - - while (slot != -1) { + base = dev->mem_start; + irq = dev->base_addr; + for (slot = startslot; (slot = dofind(&junior, slot)) != -1; slot++) { /* deduce card addresses */ getaddrs(slot, junior, &base, &irq, &medium); /* slot already in use ? */ - if (mca_is_adapter_used(slot)) { - slot = dofind(&junior, slot + 1); + if (mca_is_adapter_used(slot)) continue; - } /* were we looking for something different ? */ - if ((dev->irq != 0) || (dev->mem_start != 0)) { - if ((dev->irq != 0) && (dev->irq != irq)) { - slot = dofind(&junior, slot + 1); - continue; - } - if ((dev->mem_start != 0) - && (dev->mem_start != base)) { - slot = dofind(&junior, slot + 1); - continue; - } - } + if (dev->irq && dev->irq != irq) + continue; + if (dev->mem_start && dev->mem_start != base) + continue; /* found something that matches */ @@ -1083,8 +1091,10 @@ /* nothing found ? */ - if (slot == -1) - return ((base != 0) || (irq != 0)) ? ENXIO : ENODEV; + if (slot == -1) { + free_netdev(dev); + return (base || irq) ? ERR_PTR(-ENXIO) : ERR_PTR(-ENODEV); + } /* make procfs entries */ @@ -1102,17 +1112,14 @@ junior ? "Junior MC2" : "MC2+", slot + 1); /* allocate structure */ - priv = dev->priv = - (skmca_priv *) kmalloc(sizeof(skmca_priv), GFP_KERNEL); - if (!priv) - return -ENOMEM; + priv = dev->priv; priv->slot = slot; priv->macbase = base + 0x3fc0; priv->ioregaddr = base + 0x3ff0; priv->ctrladdr = base + 0x3ff2; priv->cmdaddr = base + 0x3ff3; priv->medium = medium; - memset(&(priv->stat), 0, sizeof(struct net_device_stats)); + memset(&priv->stat, 0, sizeof(struct net_device_stats)); spin_lock_init(&priv->lock); /* set base + irq for this device (irq not allocated so far) */ @@ -1146,9 +1153,6 @@ dev->set_multicast_list = skmca_set_multicast_list; dev->flags |= IFF_MULTICAST; - /* generic setup */ - ether_setup(dev); - /* copy out MAC address */ for (i = 0; i < 6; i++) dev->dev_addr[i] = SKMCA_READB(priv->macbase + (i << 1)); @@ -1167,7 +1171,13 @@ startslot = slot + 1; - return 0; + err = register_netdev(dev); + if (err) { + cleanup_card(dev); + free_netdev(dev); + dev = ERR_PTR(err); + } + return dev; } /* ------------------------------------------------------------------------ @@ -1179,51 +1189,34 @@ #define DEVMAX 5 -static struct net_device moddevs[DEVMAX] = { - { .name = " ", .init = skmca_probe }, - { .name = " ", .init = skmca_probe }, - { .name = " ", .init = skmca_probe }, - { .name = " ", .init = skmca_probe }, - { .name = " ", .init = skmca_probe } -}; - -int irq; -int io; +static struct net_device *moddevs[DEVMAX]; int init_module(void) { - int z, res; + int z; startslot = 0; for (z = 0; z < DEVMAX; z++) { - strcpy(moddevs[z].name, " "); - res = register_netdev(moddevs + z); - if (res != 0) - return (z > 0) ? 0 : -EIO; + struct net_device *dev = skmca_probe(-1); + if (IS_ERR(dev)) + break; + moddevs[z] = dev; } - + if (!z) + return -EIO; return 0; } void cleanup_module(void) { - struct net_device *dev; - skmca_priv *priv; int z; for (z = 0; z < DEVMAX; z++) { - dev = moddevs + z; - if (dev->priv != NULL) { - priv = (skmca_priv *) dev->priv; - DeinitBoard(dev); - if (dev->irq != 0) - free_irq(dev->irq, dev); - dev->irq = 0; + struct net_device *dev = moddevs[z]; + if (dev) { unregister_netdev(dev); - mca_mark_as_unused(priv->slot); - mca_set_adapter_procfn(priv->slot, NULL, NULL); - kfree(dev->priv); - dev->priv = NULL; + cleanup_card(dev); + free_netdev(dev); } } } diff -Nru a/drivers/net/sk_mca.h b/drivers/net/sk_mca.h --- a/drivers/net/sk_mca.h Thu Jan 22 18:59:25 2004 +++ b/drivers/net/sk_mca.h Thu Jan 22 18:59:25 2004 @@ -178,7 +178,4 @@ #endif /* _SK_MCA_DRIVER_ */ -extern int skmca_probe(struct net_device *); - - #endif /* _SK_MCA_INCLUDE_ */ diff -Nru a/drivers/net/skfp/skfddi.c b/drivers/net/skfp/skfddi.c --- a/drivers/net/skfp/skfddi.c Thu Jan 22 18:59:23 2004 +++ b/drivers/net/skfp/skfddi.c Thu Jan 22 18:59:23 2004 @@ -39,12 +39,6 @@ * are skfddi.c, h/types.h, h/osdef1st.h, h/targetos.h. * The others belong to the SysKonnect FDDI Hardware Module and * should better not be changed. - * NOTE: - * Compiling this driver produces some warnings, but I did not fix - * this, because the Hardware Module source is used for different - * drivers, and fixing it for Linux might bring problems on other - * projects. To keep the source common for all those drivers (and - * thus simplify fixes to it), please do not clean it up! * * Modification History: * Date Name Description @@ -58,6 +52,7 @@ * 07-May-00 DM 64 bit fixes, new dma interface * 31-Jul-03 DB Audit copy_*_user in skfp_ioctl * Daniele Bellucci + * 03-Dec-03 SH Convert to PCI device model * * Compilation options (-Dxxx): * DRIVERDEBUG print lots of messages to log file @@ -70,7 +65,7 @@ /* Version information string - should be updated prior to */ /* each new release!!! */ -#define VERSION "2.06" +#define VERSION "2.07" static const char *boot_msg = "SysKonnect FDDI PCI Adapter driver v" VERSION " for\n" @@ -80,15 +75,11 @@ #include #include -#include -#include #include #include #include #include #include -#include -#include // isdigit #include #include #include @@ -106,17 +97,7 @@ #include "h/smtstate.h" -// Define global routines -int skfp_probe(struct net_device *dev); - - // Define module-wide (static) routines -static struct net_device *alloc_device(struct net_device *dev, u_long iobase); -static struct net_device *insert_device(struct net_device *dev, - int (*init) (struct net_device *)); -static int fddi_dev_index(unsigned char *s); -static void init_dev(struct net_device *dev, u_long iobase); -static void link_modules(struct net_device *dev, struct net_device *tmp); static int skfp_driver_init(struct net_device *dev); static int skfp_open(struct net_device *dev); static int skfp_close(struct net_device *dev); @@ -193,15 +174,6 @@ // Define module-wide (static) variables static int num_boards; /* total number of adapters configured */ -static int num_fddi; -static int autoprobed; - -#ifdef MODULE -static struct net_device *unlink_modules(struct net_device *p); -static int loading_module = 1; -#else -static int loading_module; -#endif // MODULE #ifdef DRIVERDEBUG #define PRINTK(s, args...) printk(s, ## args) @@ -212,9 +184,9 @@ #define PRIV(dev) (&(((struct s_smc *)dev->priv)->os)) /* - * ============== - * = skfp_probe = - * ============== + * ================= + * = skfp_init_one = + * ================= * * Overview: * Probes for supported FDDI PCI controllers @@ -223,30 +195,11 @@ * Condition code * * Arguments: - * dev - pointer to device information + * pdev - pointer to PCI device information * * Functional Description: - * This routine is called by the OS for each FDDI device name (fddi0, - * fddi1,...,fddi6, fddi7) specified in drivers/net/Space.c. - * If loaded as a module, it will detect and initialize all - * adapters the first time it is called. - * - * Let's say that skfp_probe() is getting called to initialize fddi0. - * Furthermore, let's say there are three supported controllers in the - * system. Before skfp_probe() leaves, devices fddi0, fddi1, and fddi2 - * will be initialized and a global flag will be set to indicate that - * skfp_probe() has already been called. - * - * However...the OS doesn't know that we've already initialized - * devices fddi1 and fddi2 so skfp_probe() gets called again and again - * until it reaches the end of the device list for FDDI (presently, - * fddi7). It's important that the driver "pretend" to probe for - * devices fddi1 and fddi2 and return success. Devices fddi3 - * through fddi7 will return failure since they weren't initialized. - * - * This algorithm seems to work for the time being. As other FDDI - * drivers are written for Linux, a more generic approach (perhaps - * similar to the Ethernet card approach) may need to be implemented. + * This is now called by PCI driver registration process + * for each board found. * * Return Codes: * 0 - This device (fddi0, fddi1, etc) configured successfully @@ -259,374 +212,176 @@ * initialized and the board resources are read and stored in * the device structure. */ -int skfp_probe(struct net_device *dev) +static int skfp_init_one(struct pci_dev *pdev, + const struct pci_device_id *ent) { - int i; /* used in for loops */ - struct pci_dev *pdev = NULL; /* PCI device structure */ -#ifndef MEM_MAPPED_IO - u16 port; /* temporary I/O (port) address */ - int port_len; /* length of port address range (in bytes) */ -#else - unsigned long port; -#endif - u16 command; /* PCI Configuration space Command register val */ + struct net_device *dev; struct s_smc *smc; /* board pointer */ - struct net_device *tmp = dev; - u8 first_dev_used = 0; - u16 SubSysId; + u32 port, len; + int err; - PRINTK(KERN_INFO "entering skfp_probe\n"); - - /* - * Verify whether we're going through skfp_probe() again - * - * If so, see if we're going through for a subsequent fddi device that - * we've already initialized. If we are, return success (0). If not, - * return failure (-ENODEV). - */ - - if (autoprobed) { - PRINTK(KERN_INFO "Already entered skfp_probe\n"); - if (dev != NULL) { - if ((strncmp(dev->name, "fddi", 4) == 0) && - (dev->base_addr != 0)) { - return (0); - } - return (-ENODEV); - } - } - autoprobed = 1; /* set global flag */ + PRINTK(KERN_INFO "entering skfp_init_one\n"); - printk("%s\n", boot_msg); + if (num_boards == 0) + printk("%s\n", boot_msg); - /* Scan for Syskonnect FDDI PCI controllers */ - for (i = 0; i < SKFP_MAX_NUM_BOARDS; i++) { // scan for PCI cards - PRINTK(KERN_INFO "Check device %d\n", i); - if ((pdev=pci_find_device(PCI_VENDOR_ID_SK, PCI_DEVICE_ID_SK_FP, - pdev)) == 0) { - break; - } - if (pci_enable_device(pdev)) - continue; + err = pci_enable_device(pdev); + if (err) + goto err_out1; -#ifndef MEM_MAPPED_IO - /* Verify that I/O enable bit is set (PCI slot is enabled) */ - pci_read_config_word(pdev, PCI_COMMAND, &command); - if ((command & PCI_COMMAND_IO) == 0) { - PRINTK("I/O enable bit not set!"); - PRINTK(" Verify that slot is enabled\n"); - continue; - } - /* Turn off memory mapped space and enable mastering */ +#ifdef MEM_MAPPED_IO + if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) { + printk(KERN_ERR "skfp: region is not an MMIO resource\n"); + err = -EIO; + goto err_out1; + } + port = pci_resource_start(pdev, 0); + len = pci_resource_len(pdev, 0); - PRINTK(KERN_INFO "Command Reg: %04x\n", command); - command |= PCI_COMMAND_MASTER; - command &= ~PCI_COMMAND_MEMORY; - pci_write_config_word(pdev, PCI_COMMAND, command); - - /* Read I/O base address from PCI Configuration Space */ - - pci_read_config_word(pdev, PCI_BASE_ADDRESS_1, &port); - port &= PCI_BASE_ADDRESS_IO_MASK; // clear I/O bit (bit 0) - - /* Verify port address range is not already being used */ - - port_len = FP_IO_LEN; - if (check_region(port, port_len) != 0) { - printk("I/O range allocated to adapter"); - printk(" (0x%X-0x%X) is already being used!\n", port, - (port + port_len - 1)); - continue; - } + if (len < 0x4000) { + printk(KERN_ERR "skfp: Invalid PCI region size: %d\n", len); + err = -EIO; + goto err_out1; + } #else - /* Verify that MEM enable bit is set (PCI slot is enabled) */ - pci_read_config_word(pdev, PCI_COMMAND, &command); - if ((command & PCI_COMMAND_MEMORY) == 0) { - PRINTK("MEMORY-I/O enable bit not set!"); - PRINTK(" Verify that slot is enabled\n"); - continue; - } - - /* Turn off IO mapped space and enable mastering */ - - PRINTK(KERN_INFO "Command Reg: %04x\n", command); - command |= PCI_COMMAND_MASTER; - command &= ~PCI_COMMAND_IO; - pci_write_config_word(pdev, PCI_COMMAND, command); - - port = pci_resource_start(pdev, 0); - - port = (unsigned long)ioremap(port, 0x4000); - if (!port){ - printk("skfp: Unable to map MEMORY register, " - "FDDI adapter will be disabled.\n"); - break; - } -#endif - - if ((!loading_module) || first_dev_used) { - /* Allocate a device structure for this adapter */ - tmp = alloc_device(dev, port); - } - first_dev_used = 1; // only significant first time - - pci_read_config_word(pdev, PCI_SUBSYSTEM_ID, &SubSysId); - - if (tmp != NULL) { - if (loading_module) - link_modules(dev, tmp); - dev = tmp; - init_dev(dev, port); - dev->irq = pdev->irq; - - /* Initialize board structure with bus-specific info */ - - smc = (struct s_smc *) dev->priv; - smc->os.dev = dev; - smc->os.bus_type = SK_BUS_TYPE_PCI; - smc->os.pdev = *pdev; - smc->os.QueueSkb = MAX_TX_QUEUE_LEN; - smc->os.MaxFrameSize = MAX_FRAME_SIZE; - smc->os.dev = dev; - smc->hw.slot = -1; - smc->os.ResetRequested = FALSE; - skb_queue_head_init(&smc->os.SendSkbQueue); - - if (skfp_driver_init(dev) == 0) { - // only increment global board - // count on success - num_boards++; - request_region(dev->base_addr, - FP_IO_LEN, dev->name); - if ((SubSysId & 0xff00) == 0x5500 || - (SubSysId & 0xff00) == 0x5800) { - printk("%s: SysKonnect FDDI PCI adapter" - " found (SK-%04X)\n", dev->name, - SubSysId); - } else { - printk("%s: FDDI PCI adapter found\n", - dev->name); - } - } else { - kfree(dev); - i = SKFP_MAX_NUM_BOARDS; // stop search - - } - - } // if (dev != NULL) - - } // for SKFP_MAX_NUM_BOARDS - - /* - * If we're at this point we're going through skfp_probe() for the - * first time. Return success (0) if we've initialized 1 or more - * boards. Otherwise, return failure (-ENODEV). - */ - - if (num_boards > 0) - return (0); - else { - printk("no SysKonnect FDDI adapter found\n"); - return (-ENODEV); + if (!(pci_resource_flags(pdev, 1) & IO_RESOURCE_IO)) { + printk(KERN_ERR "skfp: region is not PIO resource\n"); + err = -EIO; + goto err_out1; } -} // skfp_probe - - -/************************ - * - * Search the entire 'fddi' device list for a fixed probe. If a match isn't - * found then check for an autoprobe or unused device location. If they - * are not available then insert a new device structure at the end of - * the current list. - * - ************************/ -static struct net_device *alloc_device(struct net_device *dev, u_long iobase) -{ - struct net_device *adev = NULL; - int fixed = 0, new_dev = 0; - - PRINTK(KERN_INFO "entering alloc_device\n"); - if (!dev) - return dev; - num_fddi = fddi_dev_index(dev->name); - if (loading_module) { - num_fddi++; - dev = insert_device(dev, skfp_probe); - return dev; + port = pci_resource_start(pdev, 1); + len = pci_resource_len(pdev, 1); + if (len < FP_IO_LEN) { + printk(KERN_ERR "skfp: Invalid PCI region size: %d\n", + io_len); + err = -EIO; + goto err_out1; } - while (1) { - if (((dev->base_addr == NO_ADDRESS) || - (dev->base_addr == 0)) && !adev) { - adev = dev; - } else if ((dev->priv == NULL) && (dev->base_addr == iobase)) { - fixed = 1; - } else { - if (dev->next == NULL) { - new_dev = 1; - } else if (strncmp(dev->next->name, "fddi", 4) != 0) { - new_dev = 1; - } - } - if ((dev->next == NULL) || new_dev || fixed) - break; - dev = dev->next; - num_fddi++; - } // while (1) - - if (adev && !fixed) { - dev = adev; - num_fddi = fddi_dev_index(dev->name); - new_dev = 0; - } - if (((dev->next == NULL) && ((dev->base_addr != NO_ADDRESS) && - (dev->base_addr != 0)) && !fixed) || - new_dev) { - num_fddi++; /* New device */ - dev = insert_device(dev, skfp_probe); - } - if (dev) { - if (!dev->priv) { - /* Allocate space for private board structure */ - dev->priv = (void *) kmalloc(sizeof(struct s_smc), - GFP_KERNEL); - if (dev->priv == NULL) { - printk("%s: Could not allocate memory for", - dev->name); - printk(" private board structure!\n"); - return (NULL); - } - /* clear structure */ - memset(dev->priv, 0, sizeof(struct s_smc)); - } +#endif + err = pci_request_regions(pdev, "skfddi"); + if (err) + goto err_out1; + + pci_set_master(pdev); + + dev = alloc_fddidev(sizeof(struct s_smc)); + if (!dev) { + printk(KERN_ERR "skfp: Unable to allocate fddi device, " + "FDDI adapter will be disabled.\n"); + err = -ENOMEM; + goto err_out2; + } + +#ifdef MEM_MAPPED_IO + dev->base_addr = (unsigned long) ioremap(port, len); + if (!dev->base_addr) { + printk(KERN_ERR "skfp: Unable to map MEMORY register, " + "FDDI adapter will be disabled.\n"); + err = -EIO; + goto err_out3; } - return dev; -} // alloc_device - - - -/************************ - * - * Initialize device structure - * - ************************/ -static void init_dev(struct net_device *dev, u_long iobase) -{ - /* Initialize new device structure */ - - dev->mem_end = 0; /* shared memory isn't used */ - dev->mem_start = 0; /* shared memory isn't used */ - dev->base_addr = iobase; /* save port (I/O) base address */ - dev->if_port = 0; /* not applicable to FDDI adapters */ - dev->dma = 0; /* Bus Master DMA doesn't require channel */ - dev->irq = 0; - - netif_start_queue(dev); +#else + dev->base_addr = port; +#endif + dev->irq = pdev->irq; dev->get_stats = &skfp_ctl_get_stats; dev->open = &skfp_open; dev->stop = &skfp_close; dev->hard_start_xmit = &skfp_send_pkt; - dev->hard_header = NULL; /* set in fddi_setup() */ - dev->rebuild_header = NULL; /* set in fddi_setup() */ dev->set_multicast_list = &skfp_ctl_set_multicast_list; dev->set_mac_address = &skfp_ctl_set_mac_address; dev->do_ioctl = &skfp_ioctl; - dev->set_config = NULL; /* not supported for now &&& */ dev->header_cache_update = NULL; /* not supported */ - dev->change_mtu = NULL; /* set in fddi_setup() */ SET_MODULE_OWNER(dev); + SET_NETDEV_DEV(dev, &pdev->dev); - /* Initialize remaining device structure information */ - fddi_setup(dev); -} // init_device - - -/************************ - * - * If at end of fddi device list and can't use current entry, malloc - * one up. If memory could not be allocated, print an error message. - * -************************/ -static struct net_device *insert_device(struct net_device *dev, - int (*init) (struct net_device *)) -{ - struct net_device *new; - int len; - - PRINTK(KERN_INFO "entering insert_device\n"); - len = sizeof(struct net_device) + sizeof(struct s_smc); - new = (struct net_device *) kmalloc(len, GFP_KERNEL); - if (new == NULL) { - printk("fddi%d: Device not initialised, insufficient memory\n", - num_fddi); - return NULL; - } else { - memset((char *) new, 0, len); - new->priv = (struct s_smc *) (new + 1); - new->init = init; /* initialisation routine */ - if (!loading_module) { - new->next = dev->next; - dev->next = new; - } - /* create new device name */ - if (num_fddi > 999) { - sprintf(new->name, "fddi????"); - } else { - sprintf(new->name, "fddi%d", num_fddi); - } - } - return new; -} // insert_device - - -/************************ - * - * Get the number of a "fddiX" string - * - ************************/ -static int fddi_dev_index(unsigned char *s) -{ - int i = 0, j = 0; - - for (; *s; s++) { - if (isdigit(*s)) { - j = 1; - i = (i * 10) + (*s - '0'); - } else if (j) - break; - } - return i; -} // fddi_dev_index + /* Initialize board structure with bus-specific info */ + smc = (struct s_smc *) dev->priv; + smc->os.dev = dev; + smc->os.bus_type = SK_BUS_TYPE_PCI; + smc->os.pdev = *pdev; + smc->os.QueueSkb = MAX_TX_QUEUE_LEN; + smc->os.MaxFrameSize = MAX_FRAME_SIZE; + smc->os.dev = dev; + smc->hw.slot = -1; + smc->os.ResetRequested = FALSE; + skb_queue_head_init(&smc->os.SendSkbQueue); + + err = skfp_driver_init(dev); + if (err) + goto err_out4; + + err = register_netdev(dev); + if (err) + goto err_out5; + + ++num_boards; + pci_set_drvdata(pdev, dev); + + if ((pdev->subsystem_device & 0xff00) == 0x5500 || + (pdev->subsystem_device & 0xff00) == 0x5800) + printk("%s: SysKonnect FDDI PCI adapter" + " found (SK-%04X)\n", dev->name, + pdev->subsystem_device); + else + printk("%s: FDDI PCI adapter found\n", dev->name); + return 0; +err_out5: + if (smc->os.SharedMemAddr) + pci_free_consistent(pdev, smc->os.SharedMemSize, + smc->os.SharedMemAddr, + smc->os.SharedMemDMA); + pci_free_consistent(pdev, MAX_FRAME_SIZE, + smc->os.LocalRxBuffer, smc->os.LocalRxBufferDMA); +err_out4: +#ifdef MEM_MAPPED_IO + iounmap((void *) dev->base_addr); +#endif +err_out3: + free_netdev(dev); +err_out2: + pci_release_regions(pdev); +err_out1: + return err; +} -/************************ - * - * Used if loaded as module only. Link the device structures - * together. Needed to release them all at unload. - * -************************/ -static void link_modules(struct net_device *dev, struct net_device *tmp) +/* + * Called for each adapter board from pci_unregister_driver + */ +static void __devexit skfp_remove_one(struct pci_dev *pdev) { - struct net_device *p = dev; + struct net_device *p = pci_get_drvdata(pdev); + struct s_smc *lp = p->priv; - if (p) { - while (((struct s_smc *) (p->priv))->os.next_module) { - p = ((struct s_smc *) (p->priv))->os.next_module; - } + unregister_netdev(p); - if (dev != tmp) { - ((struct s_smc *) (p->priv))->os.next_module = tmp; - } else { - ((struct s_smc *) (p->priv))->os.next_module = NULL; - } + if (lp->os.SharedMemAddr) { + pci_free_consistent(&lp->os.pdev, + lp->os.SharedMemSize, + lp->os.SharedMemAddr, + lp->os.SharedMemDMA); + lp->os.SharedMemAddr = NULL; + } + if (lp->os.LocalRxBuffer) { + pci_free_consistent(&lp->os.pdev, + MAX_FRAME_SIZE, + lp->os.LocalRxBuffer, + lp->os.LocalRxBufferDMA); + lp->os.LocalRxBuffer = NULL; } - return; -} // link_modules - +#ifdef MEM_MAPPED_IO + iounmap((void *) p->base_addr); +#endif + pci_release_regions(pdev); + free_netdev(p); + pci_set_drvdata(pdev, NULL); +} /* * ==================== @@ -653,11 +408,11 @@ * 0 - initialization succeeded * -1 - initialization failed */ -static int skfp_driver_init(struct net_device *dev) +static int skfp_driver_init(struct net_device *dev) { struct s_smc *smc = (struct s_smc *) dev->priv; skfddi_priv *bp = PRIV(dev); - u8 val; /* used for I/O read/writes */ + int err = -EIO; PRINTK(KERN_INFO "entering skfp_driver_init\n"); @@ -666,9 +421,7 @@ smc->hw.iop = dev->base_addr; // Get the interrupt level from the PCI Configuration Table - val = dev->irq; - - smc->hw.irq = val; + smc->hw.irq = dev->irq; spin_lock_init(&bp->DriverLock); @@ -738,7 +491,7 @@ bp->LocalRxBuffer, bp->LocalRxBufferDMA); bp->LocalRxBuffer = NULL; } - return (-1); + return err; } // skfp_driver_init @@ -766,14 +519,15 @@ static int skfp_open(struct net_device *dev) { struct s_smc *smc = (struct s_smc *) dev->priv; + int err; PRINTK(KERN_INFO "entering skfp_open\n"); /* Register IRQ - support shared interrupts by passing device ptr */ - if (request_irq(dev->irq, (void *) skfp_interrupt, SA_SHIRQ, - dev->name, dev)) { - printk("%s: Requested IRQ %d is busy\n", dev->name, dev->irq); - return (-EAGAIN); - } + err = request_irq(dev->irq, (void *) skfp_interrupt, SA_SHIRQ, + dev->name, dev); + if (err) + return err; + /* * Set current address to factory MAC address * @@ -797,6 +551,7 @@ /* Disable promiscuous filter settings */ mac_drv_rx_mode(smc, RX_DISABLE_PROMISC); + netif_start_queue(dev); return (0); } // skfp_open @@ -831,7 +586,6 @@ static int skfp_close(struct net_device *dev) { struct s_smc *smc = (struct s_smc *) dev->priv; - struct sk_buff *skb; skfddi_priv *bp = PRIV(dev); CLI_FBI(); @@ -844,13 +598,8 @@ /* Deregister (free) IRQ */ free_irq(dev->irq, dev); - for (;;) { - skb = skb_dequeue(&bp->SendSkbQueue); - if (skb == NULL) - break; - bp->QueueSkb++; - dev_kfree_skb(skb); - } + skb_queue_purge(&bp->SendSkbQueue); + bp->QueueSkb = MAX_TX_QUEUE_LEN; return (0); } // skfp_close @@ -1285,6 +1034,8 @@ break; default: printk("ioctl for %s: unknow cmd: %04x\n", dev->name, ioc.cmd); + status = -EOPNOTSUPP; + } // switch return status; @@ -2538,63 +2289,21 @@ } // drv_reset_indication - -static struct net_device *mdev; +static struct pci_driver skfddi_pci_driver = { + .name = "skfddi", + .id_table = skfddi_pci_tbl, + .probe = skfp_init_one, + .remove = __devexit_p(skfp_remove_one), +}; static int __init skfd_init(void) { - struct net_device *p; - - if ((mdev = insert_device(NULL, skfp_probe)) == NULL) - return -ENOMEM; - - for (p = mdev; p != NULL; p = ((struct s_smc *)p->priv)->os.next_module) { - if (register_netdev(p) != 0) { - printk("skfddi init_module failed\n"); - return -EIO; - } - } - - return 0; + return pci_module_init(&skfddi_pci_driver); } -static struct net_device *unlink_modules(struct net_device *p) -{ - struct net_device *next = NULL; - - if (p->priv) { /* Private areas allocated? */ - struct s_smc *lp = (struct s_smc *) p->priv; - - next = lp->os.next_module; - - if (lp->os.SharedMemAddr) { - pci_free_consistent(&lp->os.pdev, - lp->os.SharedMemSize, - lp->os.SharedMemAddr, - lp->os.SharedMemDMA); - lp->os.SharedMemAddr = NULL; - } - if (lp->os.LocalRxBuffer) { - pci_free_consistent(&lp->os.pdev, - MAX_FRAME_SIZE, - lp->os.LocalRxBuffer, - lp->os.LocalRxBufferDMA); - lp->os.LocalRxBuffer = NULL; - } - release_region(p->base_addr, - (lp->os.bus_type == SK_BUS_TYPE_PCI ? FP_IO_LEN : 0)); - } - unregister_netdev(p); - printk("%s: unloaded\n", p->name); - free_netdev(p); /* Free the device structure */ - - return next; -} // unlink_modules - static void __exit skfd_exit(void) { - while (mdev) - mdev = unlink_modules(mdev); + pci_unregister_driver(&skfddi_pci_driver); } module_init(skfd_init); diff -Nru a/drivers/net/smc-mca.c b/drivers/net/smc-mca.c --- a/drivers/net/smc-mca.c Thu Jan 22 18:59:23 2004 +++ b/drivers/net/smc-mca.c Thu Jan 22 18:59:23 2004 @@ -202,22 +202,18 @@ return -ENXIO; /* Adapter found. */ - dev = alloc_etherdev(0); + dev = alloc_ei_netdev(); if(!dev) return -ENODEV; SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, gen_dev); - - rc = register_netdev(dev); - if (rc) - goto err_free_netdev; - - printk(KERN_INFO "%s: %s found in slot %d\n", - dev->name, smc_mca_adapter_names[adapter], slot + 1); - mca_device_set_name(mca_dev, smc_mca_adapter_names[adapter]); mca_device_set_claim(mca_dev, 1); + + printk(KERN_INFO "smc_mca: %s found in slot %d\n", + smc_mca_adapter_names[adapter], slot + 1); + ultra_found++; dev->base_addr = ioaddr = mca_device_transform_ioport(mca_dev, tbase); @@ -266,18 +262,18 @@ /* sanity check, shouldn't happen */ if (dev->mem_start == 0) { rc = -ENODEV; - goto err_unregister_netdev; + goto err_unclaim; } if (!request_region(ioaddr, ULTRA_IO_EXTENT, dev->name)) { rc = -ENODEV; - goto err_unregister_netdev; + goto err_unclaim; } reg4 = inb(ioaddr + 4) & 0x7f; outb(reg4, ioaddr + 4); - printk(KERN_INFO "%s: Parameters: %#3x,", dev->name, ioaddr); + printk(KERN_INFO "smc_mca[%d]: Parameters: %#3x,", slot + 1, ioaddr); for (i = 0; i < 6; i++) printk(" %2.2X", dev->dev_addr[i] = inb(ioaddr + 8 + i)); @@ -299,14 +295,6 @@ outb(reg4, ioaddr + 4); - /* Allocate dev->priv and fill in 8390 specific dev fields. - */ - - rc = ethdev_init(dev); - if (rc) { - printk (", no memory for dev->priv.\n"); - goto err_release_region; - } gen_dev->driver_data = dev; /* The 8390 isn't at the base address, so fake the offset @@ -336,16 +324,22 @@ dev->open = &ultramca_open; dev->stop = &ultramca_close_card; +#ifdef CONFIG_NET_POLL_CONTROLLER + dev->poll_controller = ei_poll; +#endif NS8390_init(dev, 0); + rc = register_netdev(dev); + if (rc) + goto err_release_region; + return 0; err_release_region: release_region(ioaddr, ULTRA_IO_EXTENT); -err_unregister_netdev: - unregister_netdev(dev); -err_free_netdev: +err_unclaim: + mca_device_set_claim(mca_dev, 0); free_netdev(dev); return rc; } @@ -463,14 +457,14 @@ struct mca_device *mca_dev = to_mca_device(gen_dev); struct net_device *dev = (struct net_device *)gen_dev->driver_data; - if(dev && dev->priv) { + if (dev) { /* NB: ultra_close_card() does free_irq */ int ioaddr = dev->base_addr - ULTRA_NIC_OFFSET; + unregister_netdev(dev); mca_device_set_claim(mca_dev, 0); release_region(ioaddr, ULTRA_IO_EXTENT); - unregister_netdev(dev); - kfree(dev->priv); + free_netdev(dev); } return 0; } diff -Nru a/drivers/net/smc-ultra.c b/drivers/net/smc-ultra.c --- a/drivers/net/smc-ultra.c Thu Jan 22 18:59:23 2004 +++ b/drivers/net/smc-ultra.c Thu Jan 22 18:59:23 2004 @@ -76,7 +76,6 @@ static unsigned int ultra_portlist[] __initdata = {0x200, 0x220, 0x240, 0x280, 0x300, 0x340, 0x380, 0}; -int ultra_probe(struct net_device *dev); static int ultra_probe1(struct net_device *dev, int ioaddr); #ifdef __ISAPNP__ @@ -122,18 +121,30 @@ #define ULTRA_IO_EXTENT 32 #define EN0_ERWCNT 0x08 /* Early receive warning count. */ +#ifdef CONFIG_NET_POLL_CONTROLLER +static void ultra_poll(struct net_device *dev) +{ + disable_irq(dev->irq); + ei_interrupt(dev->irq, dev, NULL); + enable_irq(dev->irq); +} +#endif /* Probe for the Ultra. This looks like a 8013 with the station address PROM at I/O ports +8 to +13, with a checksum following. */ -int __init ultra_probe(struct net_device *dev) +static int __init do_ultra_probe(struct net_device *dev) { int i; int base_addr = dev->base_addr; + int irq = dev->irq; SET_MODULE_OWNER(dev); +#ifdef CONFIG_NET_POLL_CONTROLLER + dev->poll_controller = &ultra_poll; +#endif if (base_addr > 0x1ff) /* Check a single specified location. */ return ultra_probe1(dev, base_addr); else if (base_addr != 0) /* Don't probe at all. */ @@ -147,13 +158,51 @@ printk(KERN_NOTICE "smc-ultra.c: No ISAPnP cards found, trying standard ones...\n"); #endif - for (i = 0; ultra_portlist[i]; i++) + for (i = 0; ultra_portlist[i]; i++) { + dev->irq = irq; if (ultra_probe1(dev, ultra_portlist[i]) == 0) return 0; + } return -ENODEV; } +static void cleanup_card(struct net_device *dev) +{ + /* NB: ultra_close_card() does free_irq */ +#ifdef __ISAPNP__ + struct pnp_dev *idev = (struct pnp_dev *)ei_status.priv; + if (idev) + pnp_device_detach(idev); +#endif + release_region(dev->base_addr - ULTRA_NIC_OFFSET, ULTRA_IO_EXTENT); +} + +struct net_device * __init ultra_probe(int unit) +{ + struct net_device *dev = alloc_ei_netdev(); + int err; + + if (!dev) + return ERR_PTR(-ENOMEM); + + sprintf(dev->name, "eth%d", unit); + netdev_boot_setup_check(dev); + + err = do_ultra_probe(dev); + if (err) + goto out; + err = register_netdev(dev); + if (err) + goto out1; + return dev; +out1: + cleanup_card(dev); +out: + free_netdev(dev); + return ERR_PTR(err); +} + static int __init ultra_probe1(struct net_device *dev, int ioaddr) { int i, retval; @@ -226,13 +275,6 @@ eeprom_irq = 1; } - /* Allocate dev->priv and fill in 8390 specific dev fields. */ - if (ethdev_init(dev)) { - printk (", no memory for dev->priv.\n"); - retval = -ENOMEM; - goto out; - } - /* The 8390 isn't at the base address, so fake the offset */ dev->base_addr = ioaddr+ULTRA_NIC_OFFSET; @@ -270,6 +312,9 @@ ei_status.reset_8390 = &ultra_reset_8390; dev->open = &ultra_open; dev->stop = &ultra_close_card; +#ifdef CONFIG_NET_POLL_CONTROLLER + dev->poll_controller = ei_poll; +#endif NS8390_init(dev, 0); return 0; @@ -500,7 +545,7 @@ #ifdef MODULE #define MAX_ULTRA_CARDS 4 /* Max number of Ultra cards per module */ -static struct net_device dev_ultra[MAX_ULTRA_CARDS]; +static struct net_device *dev_ultra[MAX_ULTRA_CARDS]; static int io[MAX_ULTRA_CARDS]; static int irq[MAX_ULTRA_CARDS]; @@ -516,26 +561,33 @@ int init_module(void) { + struct net_device *dev; int this_dev, found = 0; for (this_dev = 0; this_dev < MAX_ULTRA_CARDS; this_dev++) { - struct net_device *dev = &dev_ultra[this_dev]; - dev->irq = irq[this_dev]; - dev->base_addr = io[this_dev]; - dev->init = ultra_probe; if (io[this_dev] == 0) { if (this_dev != 0) break; /* only autoprobe 1st one */ printk(KERN_NOTICE "smc-ultra.c: Presently autoprobing (not recommended) for a single card.\n"); } - if (register_netdev(dev) != 0) { - printk(KERN_WARNING "smc-ultra.c: No SMC Ultra card found (i/o = 0x%x).\n", io[this_dev]); - if (found != 0) return 0; /* Got at least one. */ - return -ENXIO; + dev = alloc_ei_netdev(); + if (!dev) + break; + dev->irq = irq[this_dev]; + dev->base_addr = io[this_dev]; + if (do_ultra_probe(dev) == 0) { + if (register_netdev(dev) == 0) { + dev_ultra[found++] = dev; + continue; + } + cleanup_card(dev); } - found++; + free_netdev(dev); + printk(KERN_WARNING "smc-ultra.c: No SMC Ultra card found (i/o = 0x%x).\n", io[this_dev]); + break; } - - return 0; + if (found) + return 0; + return -ENXIO; } void @@ -544,20 +596,11 @@ int this_dev; for (this_dev = 0; this_dev < MAX_ULTRA_CARDS; this_dev++) { - struct net_device *dev = &dev_ultra[this_dev]; - if (dev->priv != NULL) { - /* NB: ultra_close_card() does free_irq */ - int ioaddr = dev->base_addr - ULTRA_NIC_OFFSET; - -#ifdef __ISAPNP__ - struct pnp_dev *idev = (struct pnp_dev *)ei_status.priv; - if (idev) - pnp_device_detach(idev); -#endif - + struct net_device *dev = dev_ultra[this_dev]; + if (dev) { unregister_netdev(dev); - release_region(ioaddr, ULTRA_IO_EXTENT); - kfree(dev->priv); + cleanup_card(dev); + free_netdev(dev); } } } diff -Nru a/drivers/net/smc-ultra32.c b/drivers/net/smc-ultra32.c --- a/drivers/net/smc-ultra32.c Thu Jan 22 18:59:26 2004 +++ b/drivers/net/smc-ultra32.c Thu Jan 22 18:59:26 2004 @@ -61,7 +61,6 @@ #include "8390.h" -int ultra32_probe(struct net_device *dev); static int ultra32_probe1(struct net_device *dev, int ioaddr); static int ultra32_open(struct net_device *dev); static void ultra32_reset_8390(struct net_device *dev); @@ -98,26 +97,59 @@ #define ULTRA32_CFG6 (-0x15) /* 0xc8b */ #define ULTRA32_CFG7 0x0d /* 0xcad */ +static void cleanup_card(struct net_device *dev) +{ + int ioaddr = dev->base_addr - ULTRA32_NIC_OFFSET; + /* NB: ultra32_close_card() does free_irq */ + release_region(ioaddr, ULTRA32_IO_EXTENT); +} /* Probe for the Ultra32. This looks like a 8013 with the station address PROM at I/O ports +8 to +13, with a checksum following. */ -int __init ultra32_probe(struct net_device *dev) +struct net_device * __init ultra32_probe(int unit) { - int ioaddr; - - if (!EISA_bus) return -ENODEV; + struct net_device *dev; + int base; + int irq; + int err = -ENODEV; + + if (!EISA_bus) + return ERR_PTR(-ENODEV); + + dev = alloc_ei_netdev(); + + if (!dev) + return ERR_PTR(-ENOMEM); + + if (unit >= 0) { + sprintf(dev->name, "eth%d", unit); + netdev_boot_setup_check(dev); + } SET_MODULE_OWNER(dev); - /* EISA spec allows for up to 16 slots, but 8 is typical. */ - for (ioaddr = 0x1000 + ULTRA32_BASE; ioaddr < 0x9000; ioaddr += 0x1000) - if (ultra32_probe1(dev, ioaddr) == 0) - return 0; + irq = dev->irq; - return -ENODEV; + /* EISA spec allows for up to 16 slots, but 8 is typical. */ + for (base = 0x1000 + ULTRA32_BASE; base < 0x9000; base += 0x1000) { + if (ultra32_probe1(dev, base) == 0) + break; + dev->irq = irq; + } + if (base >= 0x9000) + goto out; + err = register_netdev(dev); + if (err) + goto out1; + return dev; +out1: + cleanup_card(dev); +out: + free_netdev(dev); + return ERR_PTR(err); } static int __init ultra32_probe1(struct net_device *dev, int ioaddr) @@ -210,13 +242,6 @@ dev->irq = irq; } - /* Allocate dev->priv and fill in 8390 specific dev fields. */ - if (ethdev_init(dev)) { - printk (", no memory for dev->priv.\n"); - retval = -ENOMEM; - goto out; - } - /* The 8390 isn't at the base address, so fake the offset */ dev->base_addr = ioaddr + ULTRA32_NIC_OFFSET; @@ -243,6 +268,9 @@ ei_status.reset_8390 = &ultra32_reset_8390; dev->open = &ultra32_open; dev->stop = &ultra32_close; +#ifdef CONFIG_NET_POLL_CONTROLLER + dev->poll_controller = ei_poll; +#endif NS8390_init(dev, 0); return 0; @@ -380,7 +408,7 @@ #ifdef MODULE #define MAX_ULTRA32_CARDS 4 /* Max number of Ultra cards per module */ -static struct net_device dev_ultra[MAX_ULTRA32_CARDS]; +static struct net_device *dev_ultra[MAX_ULTRA32_CARDS]; MODULE_DESCRIPTION("SMC Ultra32 EISA ethernet driver"); MODULE_LICENSE("GPL"); @@ -390,18 +418,15 @@ int this_dev, found = 0; for (this_dev = 0; this_dev < MAX_ULTRA32_CARDS; this_dev++) { - struct net_device *dev = &dev_ultra[this_dev]; - dev->init = ultra32_probe; - if (register_netdev(dev) != 0) { - if (found > 0) { /* Got at least one. */ - return 0; - } - printk(KERN_WARNING "smc-ultra32.c: No SMC Ultra32 found.\n"); - return -ENXIO; - } - found++; + struct net_device *dev = ultra32_probe(-1); + if (IS_ERR(dev)) + break; + dev_ultra[found++] = dev; } - return 0; + if (found) + return 0; + printk(KERN_WARNING "smc-ultra32.c: No SMC Ultra32 found.\n"); + return -ENXIO; } void cleanup_module(void) @@ -409,14 +434,11 @@ int this_dev; for (this_dev = 0; this_dev < MAX_ULTRA32_CARDS; this_dev++) { - struct net_device *dev = &dev_ultra[this_dev]; - if (dev->priv != NULL) { - int ioaddr = dev->base_addr - ULTRA32_NIC_OFFSET; - void *priv = dev->priv; - /* NB: ultra32_close_card() does free_irq */ - release_region(ioaddr, ULTRA32_IO_EXTENT); + struct net_device *dev = dev_ultra[this_dev]; + if (dev) { unregister_netdev(dev); - kfree(priv); + cleanup_card(dev); + free_netdev(dev); } } } diff -Nru a/drivers/net/smc9194.c b/drivers/net/smc9194.c --- a/drivers/net/smc9194.c Thu Jan 22 18:59:26 2004 +++ b/drivers/net/smc9194.c Thu Jan 22 18:59:26 2004 @@ -191,7 +191,7 @@ . . NB:This shouldn't be static since it is referred to externally. */ -int smc_init(struct net_device *dev); +struct net_device *smc_init(int unit); /* . The kernel calls this function when someone wants to use the device, @@ -672,7 +672,7 @@ /*------------------------------------------------------------------------- | - | smc_init( struct net_device * dev ) + | smc_init(int unit) | Input parameters: | dev->base_addr == 0, try to find all possible locations | dev->base_addr == 1, return failure code @@ -680,31 +680,56 @@ | dev->base_addr == this is the address to check | | Output: - | 0 --> there is a device - | anything else, error + | pointer to net_device or ERR_PTR(error) | --------------------------------------------------------------------------- */ -int __init smc_init(struct net_device *dev) +static int io; +static int irq; +static int ifport; + +struct net_device * __init smc_init(int unit) { - int i; - int base_addr = dev->base_addr; + struct net_device *dev = alloc_etherdev(sizeof(struct smc_local)); + unsigned *port; + int err = 0; + + if (!dev) + return ERR_PTR(-ENODEV); + + if (unit >= 0) { + sprintf(dev->name, "eth%d", unit); + netdev_boot_setup_check(dev); + io = dev->base_addr; + irq = dev->irq; + } SET_MODULE_OWNER(dev); - /* try a specific location */ - if (base_addr > 0x1ff) - return smc_probe(dev, base_addr); - else if (base_addr != 0) - return -ENXIO; - - /* check every ethernet address */ - for (i = 0; smc_portlist[i]; i++) - if (smc_probe(dev, smc_portlist[i]) == 0) - return 0; - - /* couldn't find anything */ - return -ENODEV; + if (io > 0x1ff) { /* Check a single specified location. */ + err = smc_probe(dev, io); + } else if (io != 0) { /* Don't probe at all. */ + err = -ENXIO; + } else { + for (port = smc_portlist; *port; port++) { + if (smc_probe(dev, *port) == 0) + break; + } + if (!*port) + err = -ENODEV; + } + if (err) + goto out; + err = register_netdev(dev); + if (err) + goto out1; + return dev; +out1: + free_irq(dev->irq, dev); + release_region(dev->base_addr, SMC_IO_EXTENT); +out: + free_netdev(dev); + return ERR_PTR(err); } /*---------------------------------------------------------------------- @@ -821,6 +846,9 @@ if (!request_region(ioaddr, SMC_IO_EXTENT, dev->name)) return -EBUSY; + dev->irq = irq; + dev->if_port = ifport; + /* First, see if the high byte is 0x33 */ bank = inw( ioaddr + BANK_SELECT ); if ( (bank & 0xFF00) != 0x3300 ) { @@ -969,28 +997,14 @@ printk("%2.2x:", dev->dev_addr[i] ); printk("%2.2x \n", dev->dev_addr[5] ); - - /* Initialize the private structure. */ - if (dev->priv == NULL) { - dev->priv = kmalloc(sizeof(struct smc_local), GFP_KERNEL); - if (dev->priv == NULL) { - retval = -ENOMEM; - goto err_out; - } - } /* set the private data to zero by default */ memset(dev->priv, 0, sizeof(struct smc_local)); - /* Fill in the fields of the device structure with ethernet values. */ - ether_setup(dev); - /* Grab the IRQ */ retval = request_irq(dev->irq, &smc_interrupt, 0, dev->name, dev); if (retval) { printk("%s: unable to get IRQ %d (irqval=%d).\n", dev->name, dev->irq, retval); - kfree(dev->priv); - dev->priv = NULL; goto err_out; } @@ -1524,10 +1538,7 @@ #ifdef MODULE -static struct net_device devSMC9194; -static int io; -static int irq; -static int ifport; +static struct net_device *devSMC9194; MODULE_LICENSE("GPL"); MODULE_PARM(io, "i"); @@ -1539,32 +1550,23 @@ int init_module(void) { - int result; - if (io == 0) printk(KERN_WARNING CARDNAME": You shouldn't use auto-probing with insmod!\n" ); /* copy the parameters from insmod into the device structure */ - devSMC9194.base_addr = io; - devSMC9194.irq = irq; - devSMC9194.if_port = ifport; - devSMC9194.init = smc_init; - if ((result = register_netdev(&devSMC9194)) != 0) - return result; - + devSMC9194 = smc_init(-1); + if (IS_ERR(devSMC9194)) + return PTR_ERR(devSMC9194); return 0; } void cleanup_module(void) { - unregister_netdev(&devSMC9194); - - free_irq(devSMC9194.irq, &devSMC9194); - release_region(devSMC9194.base_addr, SMC_IO_EXTENT); - - if (devSMC9194.priv) - kfree(devSMC9194.priv); + unregister_netdev(devSMC9194); + free_irq(devSMC9194->irq, devSMC9194); + release_region(devSMC9194->base_addr, SMC_IO_EXTENT); + free_netdev(devSMC9194); } #endif /* MODULE */ diff -Nru a/drivers/net/stnic.c b/drivers/net/stnic.c --- a/drivers/net/stnic.c Thu Jan 22 18:59:26 2004 +++ b/drivers/net/stnic.c Thu Jan 22 18:59:26 2004 @@ -98,28 +98,20 @@ STNIC_DELAY (); } -int __init stnic_probe(void) +static int __init stnic_probe(void) { struct net_device *dev; - int i; + int i, err; /* If we are not running on a SolutionEngine, give up now */ if (! MACH_SE) return -ENODEV; /* New style probing API */ - dev = init_etherdev (NULL, 0); + dev = alloc_ei_netdev(); if (!dev) return -ENOMEM; SET_MODULE_OWNER(dev); - stnic_dev = dev; - - /* Allocate dev->priv and fill in 8390 specific dev fields. */ - if (ethdev_init (dev)) - { - printk (KERN_EMERG "Unable to get memory for dev->priv.\n"); - return -ENOMEM; - } #ifdef CONFIG_SH_STANDARD_BIOS sh_bios_get_node_addr (stnic_eadr); @@ -132,16 +124,17 @@ dev->irq = IRQ_STNIC; dev->open = &stnic_open; dev->stop = &stnic_close; +#ifdef CONFIG_NET_POLL_CONTROLLER + dev->poll_controller = ei_poll; +#endif /* Snarf the interrupt now. There's no point in waiting since we cannot share and the board will usually be enabled. */ - i = request_irq (dev->irq, ei_interrupt, 0, dev->name, dev); - if (i) { + err = request_irq (dev->irq, ei_interrupt, 0, dev->name, dev); + if (err) { printk (KERN_EMERG " unable to get IRQ %d.\n", dev->irq); - unregister_netdev(dev); - kfree(dev->priv); - kfree(dev); - return i; + free_netdev(dev); + return err; } ei_status.name = dev->name; @@ -162,6 +155,14 @@ stnic_init (dev); + err = register_netdev(dev); + if (err) { + free_irq(dev->irq, dev); + free_netdev(dev); + return err; + } + stnic_dev = dev; + printk (KERN_INFO "NS ST-NIC 83902A\n"); return 0; @@ -305,15 +306,13 @@ return; } -/* Hardware interrupt handler. */ -irqreturn_t ei_interrupt (int irq, void *dev_id, struct pt_regs *regs); - -irqreturn_t -do_stnic_intr (int irq, void *dev_id, struct pt_regs *regs) +static void __exit stnic_cleanup(void) { - return ei_interrupt (0, stnic_dev, regs); + unregister_netdev(stnic_dev); + free_irq(stnic_dev->irq, stnic_dev); + free_netdev(stnic_dev); } module_init(stnic_probe); -/* No cleanup routine. */ +module_exit(stnic_cleanup); MODULE_LICENSE("GPL"); diff -Nru a/drivers/net/sun3_82586.c b/drivers/net/sun3_82586.c --- a/drivers/net/sun3_82586.c Thu Jan 22 18:59:25 2004 +++ b/drivers/net/sun3_82586.c Thu Jan 22 18:59:25 2004 @@ -55,6 +55,7 @@ #define DEBUG /* debug on */ #define SYSBUSVAL 0 /* 16 Bit */ +#define SUN3_82586_TOTAL_SIZE PAGE_SIZE #define sun3_attn586() {*(volatile unsigned char *)(dev->base_addr) |= IEOB_ATTEN; *(volatile unsigned char *)(dev->base_addr) &= ~IEOB_ATTEN;} #define sun3_reset586() {*(volatile unsigned char *)(dev->base_addr) = 0; udelay(100); *(volatile unsigned char *)(dev->base_addr) = IEOB_NORSET;} @@ -277,10 +278,12 @@ memset((char *)p->scb,0,sizeof(struct scb_struct)); } -int __init sun3_82586_probe(struct net_device *dev) +struct net_device * __init sun3_82586_probe(int unit) { + struct net_device *dev; unsigned long ioaddr; static int found = 0; + int err = -ENOMEM; /* check that this machine has an onboard 82586 */ switch(idprom->id_machtype) { @@ -290,31 +293,51 @@ break; default: - return(-ENODEV); + return ERR_PTR(-ENODEV); } - if(found) - return -ENODEV; + if (found) + return ERR_PTR(-ENODEV); - ioaddr = (unsigned long)ioremap(IE_OBIO, PAGE_SIZE); + ioaddr = (unsigned long)ioremap(IE_OBIO, SUN3_82586_TOTAL_SIZE); + if (!ioaddr) + return ERR_PTR(-ENOMEM); found = 1; + dev = alloc_etherdev(sizeof(struct priv)); + if (!dev) + goto out; + if (unit >= 0) { + sprintf(dev->name, "eth%d", unit); + netdev_boot_setup_check(dev); + } SET_MODULE_OWNER(dev); dev->irq = IE_IRQ; dev->base_addr = ioaddr; - if(sun3_82586_probe1(dev, ioaddr) == 0) - return 0; - - return -ENODEV; + err = sun3_82586_probe1(dev, ioaddr); + if (err) + goto out1; + err = register_netdev(dev); + if (err) + goto out2; + return dev; + +out2: + release_region(ioaddr, SUN3_82586_TOTAL_SIZE); +out1: + free_netdev(dev); +out: + iounmap((void *)ioaddr); + return ERR_PTR(err); } static int __init sun3_82586_probe1(struct net_device *dev,int ioaddr) { int i, size, retval; -// if (!request_region(ioaddr, SUN3_82586_TOTAL_SIZE, dev->name)) -// return -EBUSY; + if (!request_region(ioaddr, SUN3_82586_TOTAL_SIZE, dev->name)) + return -EBUSY; /* copy in the ethernet address from the prom */ for(i = 0; i < 6 ; i++) @@ -341,16 +364,6 @@ goto out; } - dev->priv = (void *) kmalloc(sizeof(struct priv),GFP_KERNEL); - if(dev->priv == NULL) { - printk("%s: Ooops .. can't allocate private driver memory.\n",dev->name); - retval = -ENOMEM; - goto out; - } - - /* warning: we don't free it on errors */ - memset((char *) dev->priv,0,sizeof(struct priv)); - ((struct priv *) (dev->priv))->memtop = (char *)dvma_btov(dev->mem_start); ((struct priv *) (dev->priv))->base = (unsigned long) dvma_btov(0); alloc586(dev); @@ -374,11 +387,9 @@ dev->set_multicast_list = set_multicast_list; dev->if_port = 0; - - ether_setup(dev); - return 0; out: + release_region(ioaddr, SUN3_82586_TOTAL_SIZE); return retval; } @@ -1138,21 +1149,23 @@ #ifdef MODULE #error This code is not currently supported as a module -static struct net_device dev_sun3_82586; +static struct net_device *dev_sun3_82586; int init_module(void) { - dev_sun3_82586.init = sun3_82586_probe; - if (register_netdev(&dev_sun3_82586) != 0) - return -EIO; + dev_sun3_82586 = sun3_82586_probe(-1); + if (IS_ERR(dev_sun3_82586)) + return PTR_ERR(dev_sun3_82586); return 0; } void cleanup_module(void) { - unregister_netdev(&dev_sun3_82586); - kfree(dev_sun3_82586.priv); - dev_sun3_82586.priv = NULL; + unsigned long ioaddr = dev_sun3_82586->base_addr; + unregister_netdev(dev_sun3_82586); + release_region(ioaddr, SUN3_82586_TOTAL_SIZE); + iounmap((void *)ioaddr); + free_netdev(dev_sun3_82586); } #endif /* MODULE */ diff -Nru a/drivers/net/sun3lance.c b/drivers/net/sun3lance.c --- a/drivers/net/sun3lance.c Thu Jan 22 18:59:26 2004 +++ b/drivers/net/sun3lance.c Thu Jan 22 18:59:26 2004 @@ -246,9 +246,11 @@ /************************* End of Prototypes **************************/ -int __init sun3lance_probe( struct net_device *dev ) -{ +struct net_device * __init sun3lance_probe(int unit) +{ + struct net_device *dev; static int found; + int err = -ENODEV; /* check that this machine has an onboard lance */ switch(idprom->id_machtype) { @@ -259,18 +261,37 @@ break; default: - return(-ENODEV); + return ERR_PTR(-ENODEV); } - if(found) - return(-ENODEV); + if (found) + return ERR_PTR(-ENODEV); - if (lance_probe(dev)) { - found = 1; - return( 0 ); + dev = alloc_etherdev(sizeof(struct lance_private)); + if (!dev) + return ERR_PTR(-ENOMEM); + if (unit >= 0) { + sprintf(dev->name, "eth%d", unit); + netdev_boot_setup_check(dev); } + SET_MODULE_OWNER(dev); + + if (!lance_probe(dev)) + goto out; - return( -ENODEV ); + err = register_netdev(dev); + if (err) + goto out1; + found = 1; + return dev; + +out1: +#ifdef CONFIG_SUN3 + iounmap((void *)dev->base_addr); +#endif +out: + free_netdev(dev); + return ERR_PTR(err); } static int __init lance_probe( struct net_device *dev) @@ -285,6 +306,8 @@ #ifdef CONFIG_SUN3 ioaddr = (unsigned long)ioremap(LANCE_OBIO, PAGE_SIZE); + if (!ioaddr) + return 0; #else ioaddr = SUN3X_LANCE; #endif @@ -303,17 +326,15 @@ ioaddr_probe[0] = tmp1; ioaddr_probe[1] = tmp2; +#ifdef CONFIG_SUN3 + iounmap((void *)ioaddr); +#endif return 0; } - init_etherdev( dev, sizeof(struct lance_private) ); - if (!dev->priv) { - dev->priv = kmalloc( sizeof(struct lance_private), GFP_KERNEL ); - if (!dev->priv) - return 0; - } lp = (struct lance_private *)dev->priv; + /* XXX - leak? */ MEM = dvma_malloc_align(sizeof(struct lance_memory), 0x10000); lp->iobase = (volatile unsigned short *)ioaddr; @@ -921,32 +942,24 @@ #ifdef MODULE -static char devicename[9]; -static struct net_device sun3lance_dev = -{ - devicename, /* filled in by register_netdev() */ - 0, 0, 0, 0, /* memory */ - 0, 0, /* base, irq */ - 0, 0, 0, NULL, sun3lance_probe, -}; +static struct net_device *sun3lance_dev; int init_module(void) { - int err; - - if ((err = register_netdev( &sun3lance_dev ))) { - if (err == -EIO) { - printk( "SUN3 Lance not detected. Module not loaded.\n"); - } - return( err ); - } - return( 0 ); + sun3lance_dev = sun3lance_probe(-1); + if (IS_ERR(sun3lance_dev)) + return PTR_ERR(sun3lance_dev); + return 0; } void cleanup_module(void) { - unregister_netdev( &sun3lance_dev ); + unregister_netdev(sun3lance_dev); +#ifdef CONFIG_SUN3 + iounmap((void *)sun3lance_dev->base_addr); +#endif + free_netdev(sun3lance_dev); } #endif /* MODULE */ diff -Nru a/drivers/net/tc35815.c b/drivers/net/tc35815.c --- a/drivers/net/tc35815.c Thu Jan 22 18:59:23 2004 +++ b/drivers/net/tc35815.c Thu Jan 22 18:59:23 2004 @@ -463,7 +463,6 @@ static void tc35815_chip_reset(struct net_device *dev); static void tc35815_chip_init(struct net_device *dev); static void tc35815_phy_chip_init(struct net_device *dev); -static int tc35815_proc_info(char *buffer, char **start, off_t offset, int length, int *eof, void *data); /* A list of all installed tc35815 devices. */ static struct net_device *root_tc35815_dev = NULL; @@ -482,78 +481,76 @@ tc35815_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { - static int called = 0; int err = 0; int ret; + unsigned long pci_memaddr; + unsigned int pci_irq_line; - if (called) - return -ENODEV; - called++; + printk(KERN_INFO "tc35815_probe: found device %#08x.%#08x\n", ent->vendor, ent->device); - if (pdev) { - unsigned int pci_memaddr; - unsigned int pci_irq_line; + err = pci_enable_device(pdev); + if (err) + return err; - printk(KERN_INFO "tc35815_probe: found device %#08x.%#08x\n", ent->vendor, ent->device); + pci_memaddr = pci_resource_start (pdev, 1); - pci_memaddr = pci_resource_start (pdev, 1); + printk(KERN_INFO " pci_memaddr=%#08lx resource_flags=%#08lx\n", pci_memaddr, pci_resource_flags (pdev, 0)); - printk(KERN_INFO " pci_memaddr=%#08lx resource_flags=%#08lx\n", pci_memaddr, pci_resource_flags (pdev, 0)); + if (!pci_memaddr) { + printk(KERN_WARNING "no PCI MEM resources, aborting\n"); + ret = -ENODEV; + goto err_out; + } + pci_irq_line = pdev->irq; + /* irq disabled. */ + if (pci_irq_line == 0) { + printk(KERN_WARNING "no PCI irq, aborting\n"); + ret = -ENODEV; + goto err_out; + } - if (!pci_memaddr) { - printk(KERN_WARNING "no PCI MEM resources, aborting\n"); - return -ENODEV; - } - pci_irq_line = pdev->irq; - /* irq disabled. */ - if (pci_irq_line == 0) { - printk(KERN_WARNING "no PCI irq, aborting\n"); - return -ENODEV; - } + ret = tc35815_probe1(pdev, pci_memaddr, pci_irq_line); + if (ret) + goto err_out; - ret = tc35815_probe1(pdev, pci_memaddr, pci_irq_line); + pci_set_master(pdev); - if (!ret) { - if ((err = pci_enable_device(pdev)) < 0) { - printk(KERN_ERR "tc35815_probe: failed to enable device -- err=%d\n", err); - return err; - } - pci_set_master(pdev); - } + return 0; - return ret; - } - return -ENODEV; +err_out: + pci_disable_device(pdev); + return ret; } static int __devinit tc35815_probe1(struct pci_dev *pdev, unsigned int base_addr, unsigned int irq) { static unsigned version_printed = 0; - int i; + int i, ret; struct tc35815_local *lp; struct tc35815_regs *tr; struct net_device *dev; /* Allocate a new 'dev' if needed. */ - dev = init_etherdev(NULL, sizeof(struct tc35815_local)); + dev = alloc_etherdev(sizeof(struct tc35815_local)); if (dev == NULL) return -ENOMEM; /* - * init_etherdev allocs and zeros dev->priv + * alloc_etherdev allocs and zeros dev->priv */ lp = dev->priv; if (tc35815_debug && version_printed++ == 0) printk(KERN_DEBUG "%s", version); - printk(KERN_INFO "%s: %s found at %#x, irq %d\n", - dev->name, cardname, base_addr, irq); - /* Fill in the 'dev' fields. */ dev->irq = irq; dev->base_addr = (unsigned long)ioremap(base_addr, sizeof(struct tc35815_regs)); + if (!dev->base_addr) { + ret = -ENOMEM; + goto err_out; + } tr = (struct tc35815_regs*)dev->base_addr; tc35815_chip_reset(dev); @@ -570,9 +567,6 @@ dev->dev_addr[i] = data & 0xff; dev->dev_addr[i+1] = data >> 8; } - for (i = 0; i < 6; i++) - printk(" %2.2x", dev->dev_addr[i]); - printk("\n"); /* Initialize the device structure. */ lp->pdev = pdev; @@ -594,8 +588,6 @@ /* do auto negotiation */ tc35815_phy_chip_init(dev); - printk(KERN_INFO "%s: linkspeed %dMbps, %s Duplex\n", - dev->name, lp->linkspeed, lp->fullduplex ? "Full" : "Half"); dev->open = tc35815_open; dev->stop = tc35815_close; @@ -604,20 +596,34 @@ dev->hard_start_xmit = tc35815_send_packet; dev->get_stats = tc35815_get_stats; dev->set_multicast_list = tc35815_set_multicast_list; + SET_MODULE_OWNER(dev); -#if 0 /* XXX called in init_etherdev */ - /* Fill in the fields of the device structure with ethernet values. */ - ether_setup(dev); -#endif + ret = register_netdev(dev); + if (ret) + goto err_out_iounmap; + + printk(KERN_INFO "%s: %s found at %#x, irq %d, MAC", + dev->name, cardname, base_addr, irq); + for (i = 0; i < 6; i++) + printk(" %2.2x", dev->dev_addr[i]); + printk("\n"); + printk(KERN_INFO "%s: linkspeed %dMbps, %s Duplex\n", + dev->name, lp->linkspeed, lp->fullduplex ? "Full" : "Half"); return 0; + +err_out_iounmap: + iounmap((void *) dev->base_addr); +err_out: + free_netdev(dev); + return ret; } static int tc35815_init_queues(struct net_device *dev) { - struct tc35815_local *lp = (struct tc35815_local *)dev->priv; + struct tc35815_local *lp = dev->priv; int i; unsigned long fd_addr; @@ -702,7 +708,7 @@ static void tc35815_clear_queues(struct net_device *dev) { - struct tc35815_local *lp = (struct tc35815_local *)dev->priv; + struct tc35815_local *lp = dev->priv; int i; for (i = 0; i < TX_FD_NUM; i++) { @@ -719,7 +725,7 @@ static void tc35815_free_queues(struct net_device *dev) { - struct tc35815_local *lp = (struct tc35815_local *)dev->priv; + struct tc35815_local *lp = dev->priv; int i; if (lp->tfd_base) { @@ -805,7 +811,7 @@ static void panic_queues(struct net_device *dev) { - struct tc35815_local *lp = (struct tc35815_local *)dev->priv; + struct tc35815_local *lp = dev->priv; int i; printk("TxFD base %p, start %d, end %d\n", @@ -823,6 +829,7 @@ panic("%s: Illegal queue state.", dev->name); } +#if 0 static void print_buf(char *add, int length) { int i; @@ -839,6 +846,7 @@ } printk("\n"); } +#endif static void print_eth(char *add) { @@ -864,7 +872,7 @@ static int tc35815_open(struct net_device *dev) { - struct tc35815_local *lp = (struct tc35815_local *)dev->priv; + struct tc35815_local *lp = dev->priv; /* * This is used if the interrupt line can turned off (shared). * See 3c503.c for an example of selecting the IRQ at config-time. @@ -888,19 +896,17 @@ lp->tbusy = 0; netif_start_queue(dev); - MOD_INC_USE_COUNT; - return 0; } static void tc35815_tx_timeout(struct net_device *dev) { - struct tc35815_local *lp = (struct tc35815_local *)dev->priv; + struct tc35815_local *lp = dev->priv; struct tc35815_regs *tr = (struct tc35815_regs *)dev->base_addr; - int flags; + unsigned long flags; spin_lock_irqsave(&lp->lock, flags); - printk(KERN_WARNING "%s: transmit timed out, status %#x\n", + printk(KERN_WARNING "%s: transmit timed out, status %#lx\n", dev->name, tc_readl(&tr->Tx_Stat)); /* Try to restart the adaptor. */ tc35815_chip_reset(dev); @@ -914,7 +920,7 @@ static int tc35815_send_packet(struct sk_buff *skb, struct net_device *dev) { - struct tc35815_local *lp = (struct tc35815_local *)dev->priv; + struct tc35815_local *lp = dev->priv; struct tc35815_regs *tr = (struct tc35815_regs *)dev->base_addr; if (netif_queue_stopped(dev)) { @@ -925,7 +931,7 @@ int tickssofar = jiffies - dev->trans_start; if (tickssofar < 5) return 1; - printk(KERN_WARNING "%s: transmit timed out, status %#x\n", + printk(KERN_WARNING "%s: transmit timed out, status %#lx\n", dev->name, tc_readl(&tr->Tx_Stat)); /* Try to restart the adaptor. */ tc35815_chip_reset(dev); @@ -947,7 +953,7 @@ short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; unsigned char *buf = skb->data; struct TxFD *txfd = &lp->tfd_base[lp->tfd_start]; - int flags; + unsigned long flags; lp->stats.tx_bytes += skb->len; @@ -1051,7 +1057,7 @@ } tr = (struct tc35815_regs*)dev->base_addr; - lp = (struct tc35815_local *)dev->priv; + lp = dev->priv; do { status = tc_readl(&tr->Int_Src); @@ -1107,7 +1113,7 @@ static void tc35815_rx(struct net_device *dev) { - struct tc35815_local *lp = (struct tc35815_local *)dev->priv; + struct tc35815_local *lp = dev->priv; struct tc35815_regs *tr = (struct tc35815_regs*)dev->base_addr; unsigned int fdctl; int i; @@ -1157,7 +1163,9 @@ offset += len; cur_bd++; } - // print_buf(data,pkt_len); +#if 0 + print_buf(data,pkt_len); +#endif if (tc35815_debug > 3) print_eth(data); skb->protocol = eth_type_trans(skb, dev); @@ -1247,7 +1255,7 @@ static void tc35815_check_tx_stat(struct net_device *dev, int status) { - struct tc35815_local *lp = (struct tc35815_local *)dev->priv; + struct tc35815_local *lp = dev->priv; const char *msg = NULL; /* count collisions */ @@ -1304,7 +1312,7 @@ static void tc35815_txdone(struct net_device *dev) { - struct tc35815_local *lp = (struct tc35815_local *)dev->priv; + struct tc35815_local *lp = dev->priv; struct tc35815_regs *tr = (struct tc35815_regs*)dev->base_addr; struct TxFD *txfd; unsigned int fdctl; @@ -1379,7 +1387,7 @@ static int tc35815_close(struct net_device *dev) { - struct tc35815_local *lp = (struct tc35815_local *)dev->priv; + struct tc35815_local *lp = dev->priv; lp->tbusy = 1; netif_stop_queue(dev); @@ -1391,8 +1399,6 @@ tc35815_free_queues(dev); - MOD_DEC_USE_COUNT; - return 0; } @@ -1402,7 +1408,7 @@ */ static struct net_device_stats *tc35815_get_stats(struct net_device *dev) { - struct tc35815_local *lp = (struct tc35815_local *)dev->priv; + struct tc35815_local *lp = dev->priv; struct tc35815_regs *tr = (struct tc35815_regs*)dev->base_addr; unsigned long flags; @@ -1456,7 +1462,7 @@ int i; for (i = cam_index / 4; i < cam_index / 4 + 2; i++) { tc_writel(i * 4, &tr->CAM_Adr); - printk("CAM 0x%x: %08x", + printk("CAM 0x%x: %08lx", i * 4, tc_readl(&tr->CAM_Data)); } } @@ -1513,9 +1519,9 @@ static unsigned long tc_phy_read(struct net_device *dev, struct tc35815_regs *tr, int phy, int phy_reg) { - struct tc35815_local *lp = (struct tc35815_local *)dev->priv; + struct tc35815_local *lp = dev->priv; unsigned long data; - int flags; + unsigned long flags; spin_lock_irqsave(&lp->lock, flags); @@ -1529,8 +1535,8 @@ static void tc_phy_write(struct net_device *dev, unsigned long d, struct tc35815_regs *tr, int phy, int phy_reg) { - struct tc35815_local *lp = (struct tc35815_local *)dev->priv; - int flags; + struct tc35815_local *lp = dev->priv; + unsigned long flags; spin_lock_irqsave(&lp->lock, flags); @@ -1543,7 +1549,7 @@ static void tc35815_phy_chip_init(struct net_device *dev) { - struct tc35815_local *lp = (struct tc35815_local *)dev->priv; + struct tc35815_local *lp = dev->priv; struct tc35815_regs *tr = (struct tc35815_regs*)dev->base_addr; static int first = 1; unsigned short ctl; @@ -1648,9 +1654,9 @@ static void tc35815_chip_init(struct net_device *dev) { - struct tc35815_local *lp = (struct tc35815_local *)dev->priv; + struct tc35815_local *lp = dev->priv; struct tc35815_regs *tr = (struct tc35815_regs*)dev->base_addr; - int flags; + unsigned long flags; unsigned long txctl = TX_CTL_CMD; tc35815_phy_chip_init(dev); @@ -1694,40 +1700,6 @@ tc_writel(virt_to_bus(lp->tfd_base), &tr->TxFrmPtr); /* start DMA transmitter */ #endif spin_unlock_irqrestore(&lp->lock, flags); -} - -static int tc35815_proc_info(char *buffer, char **start, off_t offset, int length, int *eof, void *data) -{ - int len = 0; - off_t pos = 0; - off_t begin = 0; - struct net_device *dev; - - len += sprintf(buffer, "TC35815 statistics:\n"); - for (dev = root_tc35815_dev; dev; dev = ((struct tc35815_local *)dev->priv)->next_module) { - struct tc35815_local *lp = (struct tc35815_local *)dev->priv; - len += sprintf(buffer + len, - "%s: tx_ints %d, rx_ints %d, max_tx_qlen %d\n", - dev->name, - lp->lstats.tx_ints, - lp->lstats.rx_ints, - lp->lstats.max_tx_qlen); - pos = begin + len; - - if (pos < offset) { - len = 0; - begin = pos; - } - - if (pos > offset+length) break; - } - - *start = buffer + (offset - begin); - len -= (offset - begin); - - if (len > length) len = length; - - return len; } /* XXX */ diff -Nru a/drivers/net/tg3.c b/drivers/net/tg3.c --- a/drivers/net/tg3.c Thu Jan 22 18:59:25 2004 +++ b/drivers/net/tg3.c Thu Jan 22 18:59:25 2004 @@ -2479,6 +2479,13 @@ static int tg3_init_hw(struct tg3 *); static int tg3_halt(struct tg3 *); +#ifdef CONFIG_NET_POLL_CONTROLLER +static void tg3_poll_controller(struct net_device *dev) +{ + tg3_interrupt(dev->irq, dev, NULL); +} +#endif + static void tg3_reset_task(void *_data) { struct tg3 *tp = _data; @@ -7665,6 +7672,9 @@ dev->watchdog_timeo = TG3_TX_TIMEOUT; dev->change_mtu = tg3_change_mtu; dev->irq = pdev->irq; +#ifdef CONFIG_NET_POLL_CONTROLLER + dev->poll_controller = tg3_poll_controller; +#endif err = tg3_get_invariants(tp); if (err) { diff -Nru a/drivers/net/tlan.c b/drivers/net/tlan.c --- a/drivers/net/tlan.c Thu Jan 22 18:59:23 2004 +++ b/drivers/net/tlan.c Thu Jan 22 18:59:23 2004 @@ -814,6 +814,14 @@ } /* TLan_EisaProbe */ +#ifdef CONFIG_NET_POLL_CONTROLLER +static void TLan_Poll(struct net_device *dev) +{ + disable_irq(dev->irq); + TLan_HandleInterrupt(dev->irq, dev, NULL); + enable_irq(dev->irq); +} +#endif @@ -893,6 +901,9 @@ dev->get_stats = &TLan_GetStats; dev->set_multicast_list = &TLan_SetMulticastList; dev->do_ioctl = &TLan_ioctl; +#ifdef CONFIG_NET_POLL_CONTROLLER + dev->poll_controller = &TLan_Poll; +#endif dev->tx_timeout = &TLan_tx_timeout; dev->watchdog_timeo = TX_TIMEOUT; diff -Nru a/drivers/net/tokenring/3c359.c b/drivers/net/tokenring/3c359.c --- a/drivers/net/tokenring/3c359.c Thu Jan 22 18:59:27 2004 +++ b/drivers/net/tokenring/3c359.c Thu Jan 22 18:59:27 2004 @@ -314,7 +314,6 @@ dev->irq=pdev->irq; dev->base_addr=pci_resource_start(pdev,0) ; - dev->init=NULL ; /* Must be null with new api, otherwise get called twice */ xl_priv->xl_card_name = pci_name(pdev); xl_priv->xl_mmio=ioremap(pci_resource_start(pdev,1), XL_IO_SPACE); xl_priv->pdev = pdev ; @@ -332,7 +331,7 @@ if((i = xl_init(dev))) { iounmap(xl_priv->xl_mmio) ; - kfree(dev) ; + free_netdev(dev) ; pci_release_regions(pdev) ; return i ; } @@ -352,7 +351,7 @@ printk(KERN_ERR "3C359, register netdev failed\n") ; pci_set_drvdata(pdev,NULL) ; iounmap(xl_priv->xl_mmio) ; - kfree(dev) ; + free_netdev(dev) ; pci_release_regions(pdev) ; return i ; } @@ -1130,7 +1129,7 @@ xl_freemem(dev) ; free_irq(dev->irq,dev); unregister_netdev(dev) ; - kfree(dev) ; + free_netdev(dev) ; xl_reset(dev) ; writel(ACK_INTERRUPT | LATCH_ACK, xl_mmio + MMIO_COMMAND) ; spin_unlock(&xl_priv->xl_lock) ; diff -Nru a/drivers/net/tokenring/abyss.c b/drivers/net/tokenring/abyss.c --- a/drivers/net/tokenring/abyss.c Thu Jan 22 18:59:24 2004 +++ b/drivers/net/tokenring/abyss.c Thu Jan 22 18:59:24 2004 @@ -181,7 +181,7 @@ err_out_region: release_region(pci_ioaddr, ABYSS_IO_EXTENT); err_out_trdev: - kfree(dev); + free_netdev(dev); return ret; } diff -Nru a/drivers/net/tokenring/ibmtr.c b/drivers/net/tokenring/ibmtr.c --- a/drivers/net/tokenring/ibmtr.c Thu Jan 22 18:59:25 2004 +++ b/drivers/net/tokenring/ibmtr.c Thu Jan 22 18:59:25 2004 @@ -187,7 +187,7 @@ #define TRC_INITV 0x02 /* verbose init trace points */ unsigned char ibmtr_debug_trace = 0; -int ibmtr_probe(struct net_device *dev); +static int ibmtr_probe(struct net_device *dev); static int ibmtr_probe1(struct net_device *dev, int ioaddr); static unsigned char get_sram_size(struct tok_info *adapt_info); static int trdev_init(struct net_device *dev); @@ -313,6 +313,39 @@ } } +static void ibmtr_cleanup_card(struct net_device *dev) +{ + if (dev->base_addr) { + outb(0,dev->base_addr+ADAPTRESET); + + schedule_timeout(TR_RST_TIME); /* wait 50ms */ + + outb(0,dev->base_addr+ADAPTRESETREL); + } + +#ifndef PCMCIA + free_irq(dev->irq, dev); + release_region(dev->base_addr, IBMTR_IO_EXTENT); + + { + struct tok_info *ti = (struct tok_info *) dev->priv; + iounmap((u32 *)ti->mmio); + iounmap((u32 *)ti->sram_virt); + } +#endif +} + +int ibmtr_probe_card(struct net_device *dev) +{ + int err = ibmtr_probe(dev); + if (!err) { + err = register_netdev(dev); + if (err) + ibmtr_cleanup_card(dev); + } + return err; +} + /**************************************************************************** * ibmtr_probe(): Routine specified in the network device structure * to probe for an IBM Token Ring Adapter. Routine outline: @@ -325,7 +358,7 @@ * which references it. ****************************************************************************/ -int __devinit ibmtr_probe(struct net_device *dev) +static int ibmtr_probe(struct net_device *dev) { int i; int base_addr = dev->base_addr; @@ -1925,23 +1958,24 @@ find_turbo_adapters(io); for (i = 0; io[i] && (i < IBMTR_MAX_ADAPTERS); i++) { + struct net_device *dev; irq[i] = 0; mem[i] = 0; - dev_ibmtr[i] = alloc_trdev(sizeof(struct tok_info)); - if (dev_ibmtr[i] == NULL) { + dev = alloc_trdev(sizeof(struct tok_info)); + if (dev == NULL) { if (i == 0) return -ENOMEM; break; } - dev_ibmtr[i]->base_addr = io[i]; - dev_ibmtr[i]->irq = irq[i]; - dev_ibmtr[i]->mem_start = mem[i]; - dev_ibmtr[i]->init = &ibmtr_probe; - if (register_netdev(dev_ibmtr[i]) != 0) { - kfree(dev_ibmtr[i]); - dev_ibmtr[i] = NULL; + dev->base_addr = io[i]; + dev->irq = irq[i]; + dev->mem_start = mem[i]; + + if (ibmtr_probe_card(dev)) { + free_netdev(dev); continue; } + dev_ibmtr[i] = dev; count++; } if (count) return 0; @@ -1957,27 +1991,9 @@ for (i = 0; i < IBMTR_MAX_ADAPTERS; i++){ if (!dev_ibmtr[i]) continue; - if (dev_ibmtr[i]->base_addr) { - outb(0,dev_ibmtr[i]->base_addr+ADAPTRESET); - - schedule_timeout(TR_RST_TIME); /* wait 50ms */ - - outb(0,dev_ibmtr[i]->base_addr+ADAPTRESETREL); - } - unregister_netdev(dev_ibmtr[i]); - free_irq(dev_ibmtr[i]->irq, dev_ibmtr[i]); - release_region(dev_ibmtr[i]->base_addr, IBMTR_IO_EXTENT); -#ifndef PCMCIA - { - struct tok_info *ti = (struct tok_info *) - dev_ibmtr[i]->priv; - iounmap((u32 *)ti->mmio); - iounmap((u32 *)ti->sram_virt); - } -#endif + ibmtr_cleanup_card(dev_ibmtr[i]); free_netdev(dev_ibmtr[i]); - dev_ibmtr[i] = NULL; } } module_exit(ibmtr_cleanup); diff -Nru a/drivers/net/tokenring/madgemc.c b/drivers/net/tokenring/madgemc.c --- a/drivers/net/tokenring/madgemc.c Thu Jan 22 18:59:26 2004 +++ b/drivers/net/tokenring/madgemc.c Thu Jan 22 18:59:26 2004 @@ -197,7 +197,7 @@ card = kmalloc(sizeof(struct madgemc_card), GFP_KERNEL); if (card==NULL) { printk("madgemc: unable to allocate card struct\n"); - kfree(dev); + free_netdev(dev); if (madgemc_card_list) return 0; return -1; @@ -360,7 +360,7 @@ kfree(card); tmsdev_term(dev); - kfree(dev); + free_netdev(dev); if (madgemc_card_list) return 0; return -1; @@ -399,7 +399,7 @@ MADGEMC_IO_EXTENT); getout1: kfree(card); - kfree(dev); + free_netdev(dev); slot++; } diff -Nru a/drivers/net/tokenring/olympic.c b/drivers/net/tokenring/olympic.c --- a/drivers/net/tokenring/olympic.c Thu Jan 22 18:59:26 2004 +++ b/drivers/net/tokenring/olympic.c Thu Jan 22 18:59:26 2004 @@ -228,7 +228,6 @@ #endif dev->irq=pdev->irq; dev->base_addr=pci_resource_start(pdev, 0); - dev->init=NULL; /* Must be NULL otherwise we get called twice */ olympic_priv->olympic_card_name = pci_name(pdev); olympic_priv->pdev = pdev; olympic_priv->olympic_mmio = ioremap(pci_resource_start(pdev,1),256); diff -Nru a/drivers/net/tokenring/proteon.c b/drivers/net/tokenring/proteon.c --- a/drivers/net/tokenring/proteon.c Thu Jan 22 18:59:26 2004 +++ b/drivers/net/tokenring/proteon.c Thu Jan 22 18:59:26 2004 @@ -63,7 +63,7 @@ static char cardname[] = "Proteon 1392\0"; -int proteon_probe(struct net_device *dev); +struct net_device *proteon_probe(int unit); static int proteon_open(struct net_device *dev); static int proteon_close(struct net_device *dev); static void proteon_read_eeprom(struct net_device *dev); @@ -89,80 +89,69 @@ outw(val, dev->base_addr + reg); } -struct proteon_card { - struct net_device *dev; - struct proteon_card *next; -}; - -static struct proteon_card *proteon_card_list; - -static int __init proteon_probe1(int ioaddr) +static int __init proteon_probe1(struct net_device *dev, int ioaddr) { unsigned char chk1, chk2; int i; + if (!request_region(ioaddr, PROTEON_IO_EXTENT, cardname)) + return -ENODEV; + + chk1 = inb(ioaddr + 0x1f); /* Get Proteon ID reg 1 */ - if (chk1 != 0x1f) - return (-1); + if (chk1 != 0x1f) + goto nodev; + chk1 = inb(ioaddr + 0x1e) & 0x07; /* Get Proteon ID reg 0 */ for (i=0; i<16; i++) { chk2 = inb(ioaddr + 0x1e) & 0x07; if (((chk1 + 1) & 0x07) != chk2) - return (-1); + goto nodev; chk1 = chk2; } + + dev->base_addr = ioaddr; return (0); +nodev: + release_region(ioaddr, PROTEON_IO_EXTENT); + return -ENODEV; } -int __init proteon_probe(struct net_device *dev) +struct net_device * __init proteon_probe(int unit) { - static int versionprinted; + struct net_device *dev = alloc_trdev(sizeof(struct net_local)); struct net_local *tp; - int i,j; - struct proteon_card *card; - -#ifndef MODULE - netdev_boot_setup_check(dev); - tr_setup(dev); -#endif + static int versionprinted; + const unsigned *port; + int j,err = 0; - SET_MODULE_OWNER(dev); - if (!dev->base_addr) - { - for(i = 0; portlist[i]; i++) - { - if (!request_region(portlist[i], PROTEON_IO_EXTENT, cardname)) - continue; + if (!dev) + return ERR_PTR(-ENOMEM); - if(proteon_probe1(portlist[i])) - { - release_region(dev->base_addr, PROTEON_IO_EXTENT); - continue; - } + if (unit >= 0) { + sprintf(dev->name, "tr%d", unit); + netdev_boot_setup_check(dev); + } - dev->base_addr = portlist[i]; - break; + SET_MODULE_OWNER(dev); + if (dev->base_addr) /* probe specific location */ + err = proteon_probe1(dev, dev->base_addr); + else { + for (port = portlist; *port; port++) { + err = proteon_probe1(dev, *port); + if (!err) + break; } - if(!dev->base_addr) - return -1; } - else - { - if (!request_region(dev->base_addr, PROTEON_IO_EXTENT, cardname)) - return -1; - - if(proteon_probe1(dev->base_addr)) - { - release_region(dev->base_addr, PROTEON_IO_EXTENT); - return -1; - } - } + if (err) + goto out4; /* At this point we have found a valid card. */ if (versionprinted++ == 0) printk(KERN_DEBUG "%s", version); + err = -EIO; if (tmsdev_init(dev, ISA_MAX_ADDRESS, NULL)) goto out4; @@ -264,14 +253,11 @@ printk(KERN_DEBUG "%s: IO: %#4lx IRQ: %d DMA: %d\n", dev->name, dev->base_addr, dev->irq, dev->dma); - /* Enlist in the card list */ - card = kmalloc(sizeof(struct proteon_card), GFP_KERNEL); - if (!card) + err = register_netdev(dev); + if (err) goto out; - card->next = proteon_card_list; - proteon_card_list = card; - card->dev = dev; - return 0; + + return dev; out: free_dma(dev->dma); out2: @@ -280,7 +266,8 @@ tmsdev_term(dev); out4: release_region(dev->base_addr, PROTEON_IO_EXTENT); - return -1; + free_netdev(dev); + return ERR_PTR(err); } /* @@ -370,50 +357,50 @@ MODULE_PARM(irq, "1-" __MODULE_STRING(ISATR_MAX_ADAPTERS) "i"); MODULE_PARM(dma, "1-" __MODULE_STRING(ISATR_MAX_ADAPTERS) "i"); -static int __init setup_card(unsigned long io, unsigned irq, unsigned char dma) +static struct net_device *proteon_dev[ISATR_MAX_ADAPTERS]; + +static struct net_device * __init setup_card(unsigned long io, unsigned irq, unsigned char dma) { - int res = -ENOMEM; - struct proteon_card *this_card; - struct net_device *dev = alloc_trdev(0); - - if (dev) { - dev->base_addr = io; - dev->irq = irq; - dev->dma = dma; - res = -ENODEV; - if (proteon_probe(dev) == 0) { - res = register_netdev(dev); - if (!res) - return 0; - release_region(dev->base_addr, PROTEON_IO_EXTENT); - free_irq(dev->irq, dev); - free_dma(dev->dma); - tmsdev_term(dev); - this_card = proteon_card_list; - proteon_card_list = this_card->next; - kfree(this_card); - } - kfree(dev); - } - return res; + struct net_device *dev = alloc_trdev(sizeof(struct net_local)); + int err; + + if (!dev) + return ERR_PTR(-ENOMEM); + + dev->irq = irq; + dev->dma = dma; + err = proteon_probe1(dev, io); + if (err) + goto out; + + err = register_netdev(dev); + if (err) + goto out1; + return dev; + out1: + release_region(dev->base_addr, PROTEON_IO_EXTENT); + free_irq(dev->irq, dev); + free_dma(dev->dma); + tmsdev_term(dev); + out: + free_netdev(dev); + return ERR_PTR(err); } int init_module(void) { - int i, num; + struct net_device *dev; + int i, num = 0; - num = 0; - if (io[0]) { /* Only probe addresses from command line */ - for (i = 0; i < ISATR_MAX_ADAPTERS ; i++) { - if (io[i] && setup_card(io[i], irq[i], dma[i]) == 0) - num++; - } - } else { - for(i = 0; num < ISATR_MAX_ADAPTERS && portlist[i]; i++) { - if (setup_card(portlist[i], irq[num], dma[num]) == 0) - num++; + for (i = 0; i < ISATR_MAX_ADAPTERS ; i++) { + dev = io[0] ? setup_card(io[i], irq[i], dma[i]) + : proteon_probe(-1); + if (!IS_ERR(dev)) { + proteon_dev[i] = dev; + ++num; } } + printk(KERN_NOTICE "proteon.c: %d cards found.\n", num); /* Probe for cards. */ if (num == 0) { @@ -425,11 +412,13 @@ void cleanup_module(void) { - struct net_device *dev; - struct proteon_card *this_card; + int i; - while (proteon_card_list) { - dev = proteon_card_list->dev; + for (i = 0; i < ISATR_MAX_ADAPTERS ; i++) { + struct net_device *dev = proteon_dev[i]; + + if (!dev) + continue; unregister_netdev(dev); release_region(dev->base_addr, PROTEON_IO_EXTENT); @@ -437,9 +426,6 @@ free_dma(dev->dma); tmsdev_term(dev); free_netdev(dev); - this_card = proteon_card_list; - proteon_card_list = this_card->next; - kfree(this_card); } } #endif /* MODULE */ diff -Nru a/drivers/net/tokenring/skisa.c b/drivers/net/tokenring/skisa.c --- a/drivers/net/tokenring/skisa.c Thu Jan 22 18:59:23 2004 +++ b/drivers/net/tokenring/skisa.c Thu Jan 22 18:59:23 2004 @@ -56,7 +56,7 @@ /* A zero-terminated list of IRQs to be probed. * Used again after initial probe for sktr_chipset_init, called from sktr_open. */ -static unsigned short irqlist[] = { +static const unsigned short irqlist[] = { 3, 5, 9, 10, 11, 12, 15, 0 }; @@ -69,7 +69,6 @@ static char isa_cardname[] = "SK NET TR 4/16 ISA\0"; -int sk_isa_probe(struct net_device *dev); static int sk_isa_open(struct net_device *dev); static int sk_isa_close(struct net_device *dev); static void sk_isa_read_eeprom(struct net_device *dev); @@ -95,17 +94,14 @@ outw(val, dev->base_addr + reg); } -struct sk_isa_card { - struct net_device *dev; - struct sk_isa_card *next; -}; - -static struct sk_isa_card *sk_isa_card_list; -static int __init sk_isa_probe1(int ioaddr) +static int __init sk_isa_probe1(struct net_device *dev, int ioaddr) { unsigned char old, chk1, chk2; + if (!request_region(ioaddr, SK_ISA_IO_EXTENT, isa_cardname)) + return -ENODEV; + old = inb(ioaddr + SIFADR); /* Get the old SIFADR value */ chk1 = 0; /* Begin with check value 0 */ @@ -122,8 +118,10 @@ chk2 = inb(ioaddr + SIFADD); chk2 ^= 0x0FE; - if(chk1 != chk2) - return (-1); /* No adapter */ + if(chk1 != chk2) { + release_region(ioaddr, SK_ISA_IO_EXTENT); + return -ENODEV; + } chk1 -= 2; } while(chk1 != 0); /* Repeat 128 times (all byte values) */ @@ -131,58 +129,45 @@ /* Restore the SIFADR value */ outb(old, ioaddr + SIFADR); - return (0); + dev->base_addr = ioaddr; + return 0; } -int __init sk_isa_probe(struct net_device *dev) +struct net_device * __init sk_isa_probe(int unit) { - static int versionprinted; + struct net_device *dev = alloc_trdev(sizeof(struct net_local)); struct net_local *tp; - int i,j; - struct sk_isa_card *card; + static int versionprinted; + const unsigned *port; + int j, err = 0; -#ifndef MODULE - netdev_boot_setup_check(dev); - tr_setup(dev); -#endif + if (!dev) + return ERR_PTR(-ENOMEM); - SET_MODULE_OWNER(dev); - if (!dev->base_addr) - { - for(i = 0; portlist[i]; i++) - { - if (!request_region(portlist[i], SK_ISA_IO_EXTENT, isa_cardname)) - continue; - - if(sk_isa_probe1(portlist[i])) - { - release_region(dev->base_addr, SK_ISA_IO_EXTENT); - continue; - } + if (unit >= 0) { + sprintf(dev->name, "tr%d", unit); + netdev_boot_setup_check(dev); + } - dev->base_addr = portlist[i]; - break; + SET_MODULE_OWNER(dev); + if (dev->base_addr) /* probe specific location */ + err = sk_isa_probe1(dev, dev->base_addr); + else { + for (port = portlist; *port; port++) { + err = sk_isa_probe1(dev, *port); + if (!err) + break; } - if(!dev->base_addr) - return -1; } - else - { - if (!request_region(dev->base_addr, SK_ISA_IO_EXTENT, isa_cardname)) - return -1; - - if(sk_isa_probe1(dev->base_addr)) - { - release_region(dev->base_addr, SK_ISA_IO_EXTENT); - return -1; - } - } + if (err) + goto out4; /* At this point we have found a valid card. */ if (versionprinted++ == 0) printk(KERN_DEBUG "%s", version); + err = -EIO; if (tmsdev_init(dev, ISA_MAX_ADDRESS, NULL)) goto out4; @@ -284,14 +269,11 @@ printk(KERN_DEBUG "%s: IO: %#4lx IRQ: %d DMA: %d\n", dev->name, dev->base_addr, dev->irq, dev->dma); - /* Enlist in the card list */ - card = kmalloc(sizeof(struct sk_isa_card), GFP_KERNEL); - if (!card) + err = register_netdev(dev); + if (err) goto out; - card->next = sk_isa_card_list; - sk_isa_card_list = card; - card->dev = dev; - return 0; + + return dev; out: free_dma(dev->dma); out2: @@ -300,7 +282,8 @@ tmsdev_term(dev); out4: release_region(dev->base_addr, SK_ISA_IO_EXTENT); - return -1; + free_netdev(dev); + return ERR_PTR(err); } /* @@ -373,6 +356,8 @@ #define ISATR_MAX_ADAPTERS 3 +static struct net_device *sk_isa_dev[ISATR_MAX_ADAPTERS]; + static int io[ISATR_MAX_ADAPTERS]; static int irq[ISATR_MAX_ADAPTERS]; static int dma[ISATR_MAX_ADAPTERS]; @@ -383,50 +368,54 @@ MODULE_PARM(irq, "1-" __MODULE_STRING(ISATR_MAX_ADAPTERS) "i"); MODULE_PARM(dma, "1-" __MODULE_STRING(ISATR_MAX_ADAPTERS) "i"); -static int __init setup_card(unsigned long io, unsigned irq, unsigned char dma) +static struct net_device * __init setup_card(unsigned long io, unsigned irq, unsigned char dma) { - int res = -ENOMEM; - struct sk_isa_card *this_card; - struct net_device *dev = alloc_trdev(0); - - if (dev) { - dev->base_addr = io; - dev->irq = irq; - dev->dma = dma; - res = -ENODEV; - if (sk_isa_probe(dev) == 0) { - res = register_netdev(dev); - if (!res) - return 0; - release_region(dev->base_addr, SK_ISA_IO_EXTENT); - free_irq(dev->irq, dev); - free_dma(dev->dma); - tmsdev_term(dev); - this_card = sk_isa_card_list; - sk_isa_card_list = this_card->next; - kfree(this_card); - } - kfree(dev); - } - return res; + struct net_device *dev = alloc_trdev(sizeof(struct net_local)); + int err; + + if (!dev) + return ERR_PTR(-ENOMEM); + + dev->base_addr = io; + dev->irq = irq; + dev->dma = dma; + + err = sk_isa_probe1(dev, io); + if (err) + goto out; + + err = register_netdev(dev); + if (err) + goto out1; + return dev; + + out1: + release_region(dev->base_addr, SK_ISA_IO_EXTENT); + free_irq(dev->irq, dev); + free_dma(dev->dma); + tmsdev_term(dev); + out: + free_netdev(dev); + return ERR_PTR(err); } int init_module(void) { + struct net_device *dev; int i, num; num = 0; - if (io[0]) { /* Only probe addresses from command line */ - for (i = 0; i < ISATR_MAX_ADAPTERS ; i++) { - if (io[i] && setup_card(io[i], irq[i], dma[i]) == 0) - num++; - } - } else { - for(i = 0; num < ISATR_MAX_ADAPTERS && portlist[i]; i++) { - if (setup_card(portlist[i], irq[num], dma[num]) == 0) - num++; + for (i = 0; i < ISATR_MAX_ADAPTERS ; i++) { + if (io[0]) /* Only probe addresses from command line */ + dev = setup_card(io[i], irq[i], dma[i]); + else + dev = sk_isa_probe(-1); + if (!IS_ERR(dev)) { + sk_isa_dev[i] = dev; + ++num; } } + printk(KERN_NOTICE "skisa.c: %d cards found.\n", num); /* Probe for cards. */ if (num == 0) { @@ -438,11 +427,13 @@ void cleanup_module(void) { - struct net_device *dev; - struct sk_isa_card *this_card; + int i; + + for (i = 0; i < ISATR_MAX_ADAPTERS ; i++) { + struct net_device *dev = sk_isa_dev[i]; - while (sk_isa_card_list) { - dev = sk_isa_card_list->dev; + if (!dev) + continue; unregister_netdev(dev); release_region(dev->base_addr, SK_ISA_IO_EXTENT); @@ -450,9 +441,6 @@ free_dma(dev->dma); tmsdev_term(dev); free_netdev(dev); - this_card = sk_isa_card_list; - sk_isa_card_list = this_card->next; - kfree(this_card); } } #endif /* MODULE */ diff -Nru a/drivers/net/tokenring/smctr.c b/drivers/net/tokenring/smctr.c --- a/drivers/net/tokenring/smctr.c Thu Jan 22 18:59:25 2004 +++ b/drivers/net/tokenring/smctr.c Thu Jan 22 18:59:25 2004 @@ -69,13 +69,6 @@ #define SMCTR_IO_EXTENT 20 -/* A zero-terminated list of I/O addresses to be probed. */ -static unsigned int smctr_portlist[] __initdata = { - 0x200, 0x220, 0x240, 0x260, 0x280, 0x2A0, 0x2C0, 0x2E0, 0x300, - 0x320, 0x340, 0x360, 0x380, - 0 -}; - #ifdef CONFIG_MCA static unsigned int smctr_posid = 0x6ec6; #endif @@ -219,7 +212,7 @@ static int smctr_open_tr(struct net_device *dev); /* P */ -int __init smctr_probe (struct net_device *dev); +struct net_device *smctr_probe(int unit); static int __init smctr_probe1(struct net_device *dev, int ioaddr); static int smctr_process_rx_packet(MAC_HEADER *rmf, __u16 size, struct net_device *dev, __u16 rx_status); @@ -3583,71 +3576,72 @@ return (err); } -/* Check for a network adapter of this type, and return '0 if one exists. - * If dev->base_addr == 0, probe all likely locations. - * If dev->base_addr == 1, always return failure. +/* Check for a network adapter of this type, + * and return device structure if one exists. */ -int __init smctr_probe (struct net_device *dev) +struct net_device __init *smctr_probe(int unit) { - int i; - int base_addr; + struct net_device *dev = alloc_trdev(sizeof(struct net_local)); + static const unsigned ports[] = { + 0x200, 0x220, 0x240, 0x260, 0x280, 0x2A0, 0x2C0, 0x2E0, 0x300, + 0x320, 0x340, 0x360, 0x380, 0 + }; + const unsigned *port; + int err = 0; -#ifndef MODULE - netdev_boot_setup_check(dev); - tr_setup(dev); -#endif + if (!dev) + return ERR_PTR(-ENOMEM); - base_addr = dev->base_addr; - if(base_addr > 0x1ff) /* Check a single specified location. */ - return (smctr_probe1(dev, base_addr)); - else if(base_addr != 0) /* Don't probe at all. */ - return (-ENXIO); + SET_MODULE_OWNER(dev); - for(i = 0; smctr_portlist[i]; i++) - { - int ioaddr = smctr_portlist[i]; - if (!smctr_probe1(dev, ioaddr)) - return (0); - } - - return (-ENODEV); -} + if (unit >= 0) { + sprintf(dev->name, "tr%d", unit); + netdev_boot_setup_check(dev); + } -static void cleanup_card(struct net_device *dev) -{ + if (dev->base_addr > 0x1ff) /* Check a single specified location. */ + err = smctr_probe1(dev, dev->base_addr); + else if(dev->base_addr != 0) /* Don't probe at all. */ + err =-ENXIO; + else { + for (port = ports; *port; port++) { + err = smctr_probe1(dev, *port); + if (!err) + break; + } + } + if (err) + goto out; + err = register_netdev(dev); + if (err) + goto out1; + return dev; +out1: #ifdef CONFIG_MCA - struct net_local *tp = (struct net_local *)dev->priv; - if (tp->slot_num) + { struct net_local *tp = (struct net_local *)dev->priv; + if (tp->slot_num) mca_mark_as_unused(tp->slot_num); + } #endif release_region(dev->base_addr, SMCTR_IO_EXTENT); - if (dev->irq) - free_irq(dev->irq, dev); - if (dev->priv) - kfree(dev->priv); + free_irq(dev->irq, dev); +out: + free_netdev(dev); + return ERR_PTR(err); } + static int __init smctr_probe1(struct net_device *dev, int ioaddr) { static unsigned version_printed; - struct net_local *tp; + struct net_local *tp = dev->priv; int err; __u32 *ram; if(smctr_debug && version_printed++ == 0) printk(version); - /* Setup this devices private information structure */ - tp = (struct net_local *)kmalloc(sizeof(struct net_local), - GFP_KERNEL); - if(tp == NULL) { - err = -ENOMEM; - goto out; - } - memset(tp, 0, sizeof(struct net_local)); spin_lock_init(&tp->lock); - - dev->priv = tp; dev->base_addr = ioaddr; /* Actually detect an adapter now. */ @@ -3656,7 +3650,7 @@ { if ((err = smctr_chk_mca(dev)) < 0) { err = -ENODEV; - goto out_tp; + goto out; } } @@ -3671,7 +3665,6 @@ if(err != UCODE_PRESENT && err != SUCCESS) { printk(KERN_ERR "%s: Firmware load failed (%d)\n", dev->name, err); - cleanup_card(dev); err = -EIO; goto out; } @@ -3696,8 +3689,6 @@ dev->set_multicast_list = &smctr_set_multicast_list; return (0); -out_tp: - kfree(tp); out: return err; } @@ -5669,47 +5660,59 @@ static struct net_device* dev_smctr[SMCTR_MAX_ADAPTERS]; static int io[SMCTR_MAX_ADAPTERS]; static int irq[SMCTR_MAX_ADAPTERS]; -static int mem[SMCTR_MAX_ADAPTERS]; MODULE_LICENSE("GPL"); -MODULE_PARM(io, "1-" __MODULE_STRING(SMCTR_MAX_ADAPTERS) "i"); +MODULE_PARM(io, "1-" __MODULE_STRING(SMCTR_MAX_ADAPTERS) "i"); MODULE_PARM(irq, "1-" __MODULE_STRING(SMCTR_MAX_ADAPTERS) "i"); -MODULE_PARM(mem, "1-" __MODULE_STRING(SMCTR_MAX_ADAPTERS) "i"); -MODULE_PARM(ringspeed, "1-" __MODULE_STRING(SMCTR_MAX_ADAPTERS) "i"); +MODULE_PARM(ringspeed, "i"); + +static struct net_device *setup_card(int n) +{ + struct net_device *dev = alloc_trdev(sizeof(struct net_local)); + int err; + + if (!dev) + return ERR_PTR(-ENOMEM); + + dev->irq = irq[n]; + err = smctr_probe1(dev, io[n]); + if (err) + goto out; + + err = register_netdev(dev); + if (err) + goto out1; + return dev; + out1: +#ifdef CONFIG_MCA + { struct net_local *tp = (struct net_local *)dev->priv; + if (tp->slot_num) + mca_mark_as_unused(tp->slot_num); + } +#endif + release_region(dev->base_addr, SMCTR_IO_EXTENT); + free_irq(dev->irq, dev); +out: + free_netdev(dev); + return ERR_PTR(err); +} + int init_module(void) { - int i; + int i, found = 0; + struct net_device *dev; for(i = 0; i < SMCTR_MAX_ADAPTERS; i++) { - struct net_device *dev = alloc_trdev(0); - irq[i] = 0; - mem[i] = 0; - if (!dev) - return -ENOMEM; - dev->base_addr = io[i]; - dev->irq = irq[i]; - dev->mem_start = mem[i]; - - if (smctr_probe(dev) != 0) { - kfree(dev); - if (i == 0) { - printk(KERN_ERR "%s: smctr_probe failed.\n", - cardname); - return -EIO; - } - return 0; - } - if (register_netdev(dev) != 0) { - cleanup_card(dev); - kfree(dev); - continue; - } - dev_smctr[i] = dev; + dev = io[0]? setup_card(i) : smctr_probe(-1); + if (!IS_ERR(dev)) { + ++found; + dev_smctr[i] = dev; + } } - return (0); + return found ? 0 : -ENODEV; } void cleanup_module(void) @@ -5718,9 +5721,20 @@ for(i = 0; i < SMCTR_MAX_ADAPTERS; i++) { struct net_device *dev = dev_smctr[i]; + if (dev) { + unregister_netdev(dev); - cleanup_card(dev); +#ifdef CONFIG_MCA + { struct net_local *tp = dev->priv; + if (tp->slot_num) + mca_mark_as_unused(tp->slot_num); + } +#endif + release_region(dev->base_addr, SMCTR_IO_EXTENT); + if (dev->irq) + free_irq(dev->irq, dev); + free_netdev(dev); } } diff -Nru a/drivers/net/tokenring/tms380tr.c b/drivers/net/tokenring/tms380tr.c --- a/drivers/net/tokenring/tms380tr.c Thu Jan 22 18:59:25 2004 +++ b/drivers/net/tokenring/tms380tr.c Thu Jan 22 18:59:25 2004 @@ -147,7 +147,6 @@ struct net_local* tp); /* "I" */ static int tms380tr_init_adapter(struct net_device *dev); -static int tms380tr_init_card(struct net_device *dev); static void tms380tr_init_ipb(struct net_local *tp); static void tms380tr_init_net_local(struct net_device *dev); static void tms380tr_init_opb(struct net_device *dev); @@ -232,15 +231,6 @@ } #endif -/* Dummy function */ -static int tms380tr_init_card(struct net_device *dev) -{ - if(tms380tr_debug > 3) - printk(KERN_DEBUG "%s: tms380tr_init_card\n", dev->name); - - return (0); -} - /* * Open/initialize the board. This is called sometime after * booting when the 'ifconfig' program is run. @@ -2386,7 +2376,6 @@ } /* These can be overridden by the card driver if needed */ - dev->init = tms380tr_init_card; dev->open = tms380tr_open; dev->stop = tms380tr_close; dev->do_ioctl = NULL; diff -Nru a/drivers/net/tokenring/tmspci.c b/drivers/net/tokenring/tmspci.c --- a/drivers/net/tokenring/tmspci.c Thu Jan 22 18:59:26 2004 +++ b/drivers/net/tokenring/tmspci.c Thu Jan 22 18:59:26 2004 @@ -179,7 +179,7 @@ err_out_region: release_region(pci_ioaddr, TMS_PCI_IO_EXTENT); err_out_trdev: - kfree(dev); + free_netdev(dev); return ret; } diff -Nru a/drivers/net/tulip/Kconfig b/drivers/net/tulip/Kconfig --- a/drivers/net/tulip/Kconfig Thu Jan 22 18:59:26 2004 +++ b/drivers/net/tulip/Kconfig Thu Jan 22 18:59:26 2004 @@ -68,6 +68,26 @@ obscure bugs if your mainboard has memory controller timing issues. If in doubt, say N. +config TULIP_NAPI + bool "Use NAPI RX polling " + depends on TULIP + ---help--- + This is of useful for servers and routers dealing with high network loads. + + See . + + If in doubt, say N. + +config TULIP_NAPI_HW_MITIGATION + bool "Use Interrupt Mitigation " + depends on TULIP_NAPI + ---help--- + Use HW to reduce RX interrupts. Not strict necessary since NAPI reduces + RX interrupts but itself. Although this reduces RX interrupts even at + low levels traffic at the cost of a small latency. + + If in doubt, say Y. + config DE4X5 tristate "Generic DECchip & DIGITAL EtherWORKS PCI/EISA" depends on NET_TULIP && (PCI || EISA) diff -Nru a/drivers/net/tulip/de2104x.c b/drivers/net/tulip/de2104x.c --- a/drivers/net/tulip/de2104x.c Thu Jan 22 18:59:26 2004 +++ b/drivers/net/tulip/de2104x.c Thu Jan 22 18:59:26 2004 @@ -2084,7 +2084,7 @@ err_out_disable: pci_disable_device(pdev); err_out_free: - kfree(dev); + free_netdev(dev); return rc; } diff -Nru a/drivers/net/tulip/dmfe.c b/drivers/net/tulip/dmfe.c --- a/drivers/net/tulip/dmfe.c Thu Jan 22 18:59:26 2004 +++ b/drivers/net/tulip/dmfe.c Thu Jan 22 18:59:26 2004 @@ -457,7 +457,7 @@ pci_disable_device(pdev); err_out_free: pci_set_drvdata(pdev, NULL); - kfree(dev); + free_netdev(dev); return err; } diff -Nru a/drivers/net/tulip/interrupt.c b/drivers/net/tulip/interrupt.c --- a/drivers/net/tulip/interrupt.c Thu Jan 22 18:59:24 2004 +++ b/drivers/net/tulip/interrupt.c Thu Jan 22 18:59:24 2004 @@ -19,13 +19,13 @@ #include #include - int tulip_rx_copybreak; unsigned int tulip_max_interrupt_work; -#ifdef CONFIG_NET_HW_FLOWCONTROL - +#ifdef CONFIG_TULIP_NAPI_HW_MITIGATION #define MIT_SIZE 15 +#define MIT_TABLE 15 /* We use 0 or max */ + unsigned int mit_table[MIT_SIZE+1] = { /* CRS11 21143 hardware Mitigation Control Interrupt @@ -99,16 +99,28 @@ return refilled; } +#ifdef CONFIG_TULIP_NAPI -static int tulip_rx(struct net_device *dev) +void oom_timer(unsigned long data) +{ + struct net_device *dev = (struct net_device *)data; + netif_rx_schedule(dev); +} + +int tulip_poll(struct net_device *dev, int *budget) { struct tulip_private *tp = (struct tulip_private *)dev->priv; int entry = tp->cur_rx % RX_RING_SIZE; - int rx_work_limit = tp->dirty_rx + RX_RING_SIZE - tp->cur_rx; + int rx_work_limit = *budget; int received = 0; -#ifdef CONFIG_NET_HW_FLOWCONTROL - int drop = 0, mit_sel = 0; + if (!netif_running(dev)) + goto done; + + if (rx_work_limit > dev->quota) + rx_work_limit = dev->quota; + +#ifdef CONFIG_TULIP_NAPI_HW_MITIGATION /* that one buffer is needed for mit activation; or might be a bug in the ring buffer code; check later -- JHS*/ @@ -119,6 +131,237 @@ if (tulip_debug > 4) printk(KERN_DEBUG " In tulip_rx(), entry %d %8.8x.\n", entry, tp->rx_ring[entry].status); + + do { + /* Acknowledge current RX interrupt sources. */ + outl((RxIntr | RxNoBuf), dev->base_addr + CSR5); + + + /* If we own the next entry, it is a new packet. Send it up. */ + while ( ! (tp->rx_ring[entry].status & cpu_to_le32(DescOwned))) { + s32 status = le32_to_cpu(tp->rx_ring[entry].status); + + + if (tp->dirty_rx + RX_RING_SIZE == tp->cur_rx) + break; + + if (tulip_debug > 5) + printk(KERN_DEBUG "%s: In tulip_rx(), entry %d %8.8x.\n", + dev->name, entry, status); + if (--rx_work_limit < 0) + goto not_done; + + if ((status & 0x38008300) != 0x0300) { + if ((status & 0x38000300) != 0x0300) { + /* Ingore earlier buffers. */ + if ((status & 0xffff) != 0x7fff) { + if (tulip_debug > 1) + printk(KERN_WARNING "%s: Oversized Ethernet frame " + "spanned multiple buffers, status %8.8x!\n", + dev->name, status); + tp->stats.rx_length_errors++; + } + } else if (status & RxDescFatalErr) { + /* There was a fatal error. */ + if (tulip_debug > 2) + printk(KERN_DEBUG "%s: Receive error, Rx status %8.8x.\n", + dev->name, status); + tp->stats.rx_errors++; /* end of a packet.*/ + if (status & 0x0890) tp->stats.rx_length_errors++; + if (status & 0x0004) tp->stats.rx_frame_errors++; + if (status & 0x0002) tp->stats.rx_crc_errors++; + if (status & 0x0001) tp->stats.rx_fifo_errors++; + } + } else { + /* Omit the four octet CRC from the length. */ + short pkt_len = ((status >> 16) & 0x7ff) - 4; + struct sk_buff *skb; + +#ifndef final_version + if (pkt_len > 1518) { + printk(KERN_WARNING "%s: Bogus packet size of %d (%#x).\n", + dev->name, pkt_len, pkt_len); + pkt_len = 1518; + tp->stats.rx_length_errors++; + } +#endif + /* Check if the packet is long enough to accept without copying + to a minimally-sized skbuff. */ + if (pkt_len < tulip_rx_copybreak + && (skb = dev_alloc_skb(pkt_len + 2)) != NULL) { + skb->dev = dev; + skb_reserve(skb, 2); /* 16 byte align the IP header */ + pci_dma_sync_single(tp->pdev, + tp->rx_buffers[entry].mapping, + pkt_len, PCI_DMA_FROMDEVICE); +#if ! defined(__alpha__) + eth_copy_and_sum(skb, tp->rx_buffers[entry].skb->tail, + pkt_len, 0); + skb_put(skb, pkt_len); +#else + memcpy(skb_put(skb, pkt_len), + tp->rx_buffers[entry].skb->tail, + pkt_len); +#endif + } else { /* Pass up the skb already on the Rx ring. */ + char *temp = skb_put(skb = tp->rx_buffers[entry].skb, + pkt_len); + +#ifndef final_version + if (tp->rx_buffers[entry].mapping != + le32_to_cpu(tp->rx_ring[entry].buffer1)) { + printk(KERN_ERR "%s: Internal fault: The skbuff addresses " + "do not match in tulip_rx: %08x vs. %08x %p / %p.\n", + dev->name, + le32_to_cpu(tp->rx_ring[entry].buffer1), + tp->rx_buffers[entry].mapping, + skb->head, temp); + } +#endif + + pci_unmap_single(tp->pdev, tp->rx_buffers[entry].mapping, + PKT_BUF_SZ, PCI_DMA_FROMDEVICE); + + tp->rx_buffers[entry].skb = NULL; + tp->rx_buffers[entry].mapping = 0; + } + skb->protocol = eth_type_trans(skb, dev); + + netif_receive_skb(skb); + + dev->last_rx = jiffies; + tp->stats.rx_packets++; + tp->stats.rx_bytes += pkt_len; + } + received++; + + entry = (++tp->cur_rx) % RX_RING_SIZE; + if (tp->cur_rx - tp->dirty_rx > RX_RING_SIZE/4) + tulip_refill_rx(dev); + + } + + /* New ack strategy... irq does not ack Rx any longer + hopefully this helps */ + + /* Really bad things can happen here... If new packet arrives + * and an irq arrives (tx or just due to occasionally unset + * mask), it will be acked by irq handler, but new thread + * is not scheduled. It is major hole in design. + * No idea how to fix this if "playing with fire" will fail + * tomorrow (night 011029). If it will not fail, we won + * finally: amount of IO did not increase at all. */ + } while ((inl(dev->base_addr + CSR5) & RxIntr)); + +done: + + #ifdef CONFIG_TULIP_NAPI_HW_MITIGATION + + /* We use this simplistic scheme for IM. It's proven by + real life installations. We can have IM enabled + continuesly but this would cause unnecessary latency. + Unfortunely we can't use all the NET_RX_* feedback here. + This would turn on IM for devices that is not contributing + to backlog congestion with unnecessary latency. + + We monitor the the device RX-ring and have: + + HW Interrupt Mitigation either ON or OFF. + + ON: More then 1 pkt received (per intr.) OR we are dropping + OFF: Only 1 pkt received + + Note. We only use min and max (0, 15) settings from mit_table */ + + + if( tp->flags & HAS_INTR_MITIGATION) { + if( received > 1 ) { + if( ! tp->mit_on ) { + tp->mit_on = 1; + outl(mit_table[MIT_TABLE], dev->base_addr + CSR11); + } + } + else { + if( tp->mit_on ) { + tp->mit_on = 0; + outl(0, dev->base_addr + CSR11); + } + } + } + +#endif /* CONFIG_TULIP_NAPI_HW_MITIGATION */ + + dev->quota -= received; + *budget -= received; + + tulip_refill_rx(dev); + + /* If RX ring is not full we are out of memory. */ + if (tp->rx_buffers[tp->dirty_rx % RX_RING_SIZE].skb == NULL) goto oom; + + /* Remove us from polling list and enable RX intr. */ + + netif_rx_complete(dev); + outl(tulip_tbl[tp->chip_id].valid_intrs, dev->base_addr+CSR7); + + /* The last op happens after poll completion. Which means the following: + * 1. it can race with disabling irqs in irq handler + * 2. it can race with dise/enabling irqs in other poll threads + * 3. if an irq raised after beginning loop, it will be immediately + * triggered here. + * + * Summarizing: the logic results in some redundant irqs both + * due to races in masking and due to too late acking of already + * processed irqs. But it must not result in losing events. + */ + + return 0; + + not_done: + if (!received) { + + received = dev->quota; /* Not to happen */ + } + dev->quota -= received; + *budget -= received; + + if (tp->cur_rx - tp->dirty_rx > RX_RING_SIZE/2 || + tp->rx_buffers[tp->dirty_rx % RX_RING_SIZE].skb == NULL) + tulip_refill_rx(dev); + + if (tp->rx_buffers[tp->dirty_rx % RX_RING_SIZE].skb == NULL) goto oom; + + return 1; + + + oom: /* Executed with RX ints disabled */ + + + /* Start timer, stop polling, but do not enable rx interrupts. */ + mod_timer(&tp->oom_timer, jiffies+1); + + /* Think: timer_pending() was an explicit signature of bug. + * Timer can be pending now but fired and completed + * before we did netif_rx_complete(). See? We would lose it. */ + + /* remove ourselves from the polling list */ + netif_rx_complete(dev); + + return 0; +} + +#else /* CONFIG_TULIP_NAPI */ + +static int tulip_rx(struct net_device *dev) +{ + struct tulip_private *tp = (struct tulip_private *)dev->priv; + int entry = tp->cur_rx % RX_RING_SIZE; + int rx_work_limit = tp->dirty_rx + RX_RING_SIZE - tp->cur_rx; + int received = 0; + + if (tulip_debug > 4) + printk(KERN_DEBUG " In tulip_rx(), entry %d %8.8x.\n", entry, + tp->rx_ring[entry].status); /* If we own the next entry, it is a new packet. Send it up. */ while ( ! (tp->rx_ring[entry].status & cpu_to_le32(DescOwned))) { s32 status = le32_to_cpu(tp->rx_ring[entry].status); @@ -163,11 +406,6 @@ } #endif -#ifdef CONFIG_NET_HW_FLOWCONTROL - drop = atomic_read(&netdev_dropping); - if (drop) - goto throttle; -#endif /* Check if the packet is long enough to accept without copying to a minimally-sized skbuff. */ if (pkt_len < tulip_rx_copybreak @@ -209,44 +447,9 @@ tp->rx_buffers[entry].mapping = 0; } skb->protocol = eth_type_trans(skb, dev); -#ifdef CONFIG_NET_HW_FLOWCONTROL - mit_sel = -#endif - netif_rx(skb); -#ifdef CONFIG_NET_HW_FLOWCONTROL - switch (mit_sel) { - case NET_RX_SUCCESS: - case NET_RX_CN_LOW: - case NET_RX_CN_MOD: - break; - - case NET_RX_CN_HIGH: - rx_work_limit -= NET_RX_CN_HIGH; /* additional*/ - break; - case NET_RX_DROP: - rx_work_limit = -1; - break; - default: - printk("unknown feedback return code %d\n", mit_sel); - break; - } + netif_rx(skb); - drop = atomic_read(&netdev_dropping); - if (drop) { -throttle: - rx_work_limit = -1; - mit_sel = NET_RX_DROP; - - if (tp->fc_bit) { - long ioaddr = dev->base_addr; - - /* disable Rx & RxNoBuf ints. */ - outl(tulip_tbl[tp->chip_id].valid_intrs&RX_A_NBF_STOP, ioaddr + CSR7); - set_bit(tp->fc_bit, &netdev_fc_xoff); - } - } -#endif dev->last_rx = jiffies; tp->stats.rx_packets++; tp->stats.rx_bytes += pkt_len; @@ -254,42 +457,9 @@ received++; entry = (++tp->cur_rx) % RX_RING_SIZE; } -#ifdef CONFIG_NET_HW_FLOWCONTROL - - /* We use this simplistic scheme for IM. It's proven by - real life installations. We can have IM enabled - continuesly but this would cause unnecessary latency. - Unfortunely we can't use all the NET_RX_* feedback here. - This would turn on IM for devices that is not contributing - to backlog congestion with unnecessary latency. - - We monitor the device RX-ring and have: - - HW Interrupt Mitigation either ON or OFF. - - ON: More then 1 pkt received (per intr.) OR we are dropping - OFF: Only 1 pkt received - - Note. We only use min and max (0, 15) settings from mit_table */ - - - if( tp->flags & HAS_INTR_MITIGATION) { - if((received > 1 || mit_sel == NET_RX_DROP) - && tp->mit_sel != 15 ) { - tp->mit_sel = 15; - tp->mit_change = 1; /* Force IM change */ - } - if((received <= 1 && mit_sel != NET_RX_DROP) && tp->mit_sel != 0 ) { - tp->mit_sel = 0; - tp->mit_change = 1; /* Force IM change */ - } - } - - return RX_RING_SIZE+1; /* maxrx+1 */ -#else return received; -#endif } +#endif /* CONFIG_TULIP_NAPI */ static inline unsigned int phy_interrupt (struct net_device *dev) { @@ -323,7 +493,6 @@ struct tulip_private *tp = (struct tulip_private *)dev->priv; long ioaddr = dev->base_addr; int csr5; - int entry; int missed; int rx = 0; int tx = 0; @@ -331,6 +500,11 @@ int maxrx = RX_RING_SIZE; int maxtx = TX_RING_SIZE; int maxoi = TX_RING_SIZE; +#ifdef CONFIG_TULIP_NAPI + int rxd = 0; +#else + int entry; +#endif unsigned int work_count = tulip_max_interrupt_work; unsigned int handled = 0; @@ -346,22 +520,41 @@ tp->nir++; do { + +#ifdef CONFIG_TULIP_NAPI + + if (!rxd && (csr5 & (RxIntr | RxNoBuf))) { + rxd++; + /* Mask RX intrs and add the device to poll list. */ + outl(tulip_tbl[tp->chip_id].valid_intrs&~RxPollInt, ioaddr + CSR7); + netif_rx_schedule(dev); + + if (!(csr5&~(AbnormalIntr|NormalIntr|RxPollInt|TPLnkPass))) + break; + } + + /* Acknowledge the interrupt sources we handle here ASAP + the poll function does Rx and RxNoBuf acking */ + + outl(csr5 & 0x0001ff3f, ioaddr + CSR5); + +#else /* Acknowledge all of the current interrupt sources ASAP. */ outl(csr5 & 0x0001ffff, ioaddr + CSR5); - if (tulip_debug > 4) - printk(KERN_DEBUG "%s: interrupt csr5=%#8.8x new csr5=%#8.8x.\n", - dev->name, csr5, inl(dev->base_addr + CSR5)); if (csr5 & (RxIntr | RxNoBuf)) { -#ifdef CONFIG_NET_HW_FLOWCONTROL - if ((!tp->fc_bit) || - (!test_bit(tp->fc_bit, &netdev_fc_xoff))) -#endif rx += tulip_rx(dev); tulip_refill_rx(dev); } +#endif /* CONFIG_TULIP_NAPI */ + + if (tulip_debug > 4) + printk(KERN_DEBUG "%s: interrupt csr5=%#8.8x new csr5=%#8.8x.\n", + dev->name, csr5, inl(dev->base_addr + CSR5)); + + if (csr5 & (TxNoBuf | TxDied | TxIntr | TimerInt)) { unsigned int dirty_tx; @@ -462,15 +655,8 @@ } if (csr5 & RxDied) { /* Missed a Rx frame. */ tp->stats.rx_missed_errors += inl(ioaddr + CSR8) & 0xffff; -#ifdef CONFIG_NET_HW_FLOWCONTROL - if (tp->fc_bit && !test_bit(tp->fc_bit, &netdev_fc_xoff)) { - tp->stats.rx_errors++; - tulip_start_rxtx(tp); - } -#else tp->stats.rx_errors++; tulip_start_rxtx(tp); -#endif } /* * NB: t21142_lnk_change() does a del_timer_sync(), so be careful if this @@ -504,10 +690,6 @@ if (tulip_debug > 2) printk(KERN_ERR "%s: Re-enabling interrupts, %8.8x.\n", dev->name, csr5); -#ifdef CONFIG_NET_HW_FLOWCONTROL - if (tp->fc_bit && (test_bit(tp->fc_bit, &netdev_fc_xoff))) - if (net_ratelimit()) printk("BUG!! enabling interrupt when FC off (timerintr.) \n"); -#endif outl(tulip_tbl[tp->chip_id].valid_intrs, ioaddr + CSR7); tp->ttimer = 0; oi++; @@ -520,16 +702,9 @@ /* Acknowledge all interrupt sources. */ outl(0x8001ffff, ioaddr + CSR5); if (tp->flags & HAS_INTR_MITIGATION) { -#ifdef CONFIG_NET_HW_FLOWCONTROL - if(tp->mit_change) { - outl(mit_table[tp->mit_sel], ioaddr + CSR11); - tp->mit_change = 0; - } -#else /* Josip Loncaric at ICASE did extensive experimentation to develop a good interrupt mitigation setting.*/ outl(0x8b240000, ioaddr + CSR11); -#endif } else if (tp->chip_id == LC82C168) { /* the LC82C168 doesn't have a hw timer.*/ outl(0x00, ioaddr + CSR7); @@ -537,10 +712,8 @@ } else { /* Mask all interrupting sources, set timer to re-enable. */ -#ifndef CONFIG_NET_HW_FLOWCONTROL outl(((~csr5) & 0x0001ebef) | AbnormalIntr | TimerInt, ioaddr + CSR7); outl(0x0012, ioaddr + CSR11); -#endif } break; } @@ -550,6 +723,21 @@ break; csr5 = inl(ioaddr + CSR5); + +#ifdef CONFIG_TULIP_NAPI + if (rxd) + csr5 &= ~RxPollInt; + } while ((csr5 & (TxNoBuf | + TxDied | + TxIntr | + TimerInt | + /* Abnormal intr. */ + RxDied | + TxFIFOUnderflow | + TxJabber | + TPLnkFail | + SytemError )) != 0); +#else } while ((csr5 & (NormalIntr|AbnormalIntr)) != 0); tulip_refill_rx(dev); @@ -574,6 +762,7 @@ } } } +#endif /* CONFIG_TULIP_NAPI */ if ((missed = inl(ioaddr + CSR8) & 0x1ffff)) { tp->stats.rx_dropped += missed & 0x10000 ? 0x10000 : missed; diff -Nru a/drivers/net/tulip/tulip.h b/drivers/net/tulip/tulip.h --- a/drivers/net/tulip/tulip.h Thu Jan 22 18:59:26 2004 +++ b/drivers/net/tulip/tulip.h Thu Jan 22 18:59:26 2004 @@ -126,6 +126,7 @@ CFDD_Snooze = (1 << 30), }; +#define RxPollInt (RxIntr|RxNoBuf|RxDied|RxJabber) /* The bits in the CSR5 status registers, mostly interrupt sources. */ enum status_bits { @@ -251,9 +252,9 @@ Making the Tx ring too large decreases the effectiveness of channel bonding and packet priority. There are no ill effects from too-large receive rings. */ -#define TX_RING_SIZE 16 -#define RX_RING_SIZE 32 +#define TX_RING_SIZE 32 +#define RX_RING_SIZE 128 #define MEDIA_MASK 31 #define PKT_BUF_SZ 1536 /* Size of each temporary Rx buffer. */ @@ -343,17 +344,15 @@ int flags; struct net_device_stats stats; struct timer_list timer; /* Media selection timer. */ + struct timer_list oom_timer; /* Out of memory timer. */ u32 mc_filter[2]; spinlock_t lock; spinlock_t mii_lock; unsigned int cur_rx, cur_tx; /* The next free ring entry */ unsigned int dirty_rx, dirty_tx; /* The ring entries to be free()ed. */ -#ifdef CONFIG_NET_HW_FLOWCONTROL -#define RX_A_NBF_STOP 0xffffff3f /* To disable RX and RX-NOBUF ints. */ - int fc_bit; - int mit_sel; - int mit_change; /* Signal for Interrupt Mitigtion */ +#ifdef CONFIG_TULIP_NAPI_HW_MITIGATION + int mit_on; #endif unsigned int full_duplex:1; /* Full-duplex operation requested. */ unsigned int full_duplex_lock:1; @@ -415,6 +414,10 @@ extern int tulip_rx_copybreak; irqreturn_t tulip_interrupt(int irq, void *dev_instance, struct pt_regs *regs); int tulip_refill_rx(struct net_device *dev); +#ifdef CONFIG_TULIP_NAPI +int tulip_poll(struct net_device *dev, int *budget); +#endif + /* media.c */ int tulip_mdio_read(struct net_device *dev, int phy_id, int location); @@ -438,6 +441,7 @@ extern const char * const medianame[]; extern const char tulip_media_cap[]; extern struct tulip_chip_table tulip_tbl[]; +void oom_timer(unsigned long data); extern u8 t21040_csr13[]; #ifndef USE_IO_OPS diff -Nru a/drivers/net/tulip/tulip_core.c b/drivers/net/tulip/tulip_core.c --- a/drivers/net/tulip/tulip_core.c Thu Jan 22 18:59:25 2004 +++ b/drivers/net/tulip/tulip_core.c Thu Jan 22 18:59:25 2004 @@ -14,11 +14,17 @@ */ +#include + #define DRV_NAME "tulip" +#ifdef CONFIG_TULIP_NAPI +#define DRV_VERSION "1.1.13-NAPI" /* Keep at least for test */ +#else #define DRV_VERSION "1.1.13" +#endif #define DRV_RELDATE "May 11, 2002" -#include + #include #include "tulip.h" #include @@ -247,7 +253,7 @@ static struct net_device_stats *tulip_get_stats(struct net_device *dev); static int private_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); static void set_rx_mode(struct net_device *dev); - +static void poll_tulip(struct net_device *dev); static void tulip_set_power_state (struct tulip_private *tp, @@ -466,29 +472,16 @@ to an alternate media type. */ tp->timer.expires = RUN_AT(next_tick); add_timer(&tp->timer); -} - -#ifdef CONFIG_NET_HW_FLOWCONTROL -/* Enable receiver */ -void tulip_xon(struct net_device *dev) -{ - struct tulip_private *tp = (struct tulip_private *)dev->priv; - - clear_bit(tp->fc_bit, &netdev_fc_xoff); - if (netif_running(dev)){ - - tulip_refill_rx(dev); - outl(tulip_tbl[tp->chip_id].valid_intrs, dev->base_addr+CSR7); - } -} +#ifdef CONFIG_TULIP_NAPI + init_timer(&tp->oom_timer); + tp->oom_timer.data = (unsigned long)dev; + tp->oom_timer.function = oom_timer; #endif +} static int tulip_open(struct net_device *dev) { -#ifdef CONFIG_NET_HW_FLOWCONTROL - struct tulip_private *tp = (struct tulip_private *)dev->priv; -#endif int retval; if ((retval = request_irq(dev->irq, &tulip_interrupt, SA_SHIRQ, dev->name, dev))) @@ -498,10 +491,6 @@ tulip_up (dev); -#ifdef CONFIG_NET_HW_FLOWCONTROL - tp->fc_bit = netdev_register_fc(dev, tulip_xon); -#endif - netif_start_queue (dev); return 0; @@ -582,10 +571,7 @@ #endif /* Stop and restart the chip's Tx processes . */ -#ifdef CONFIG_NET_HW_FLOWCONTROL - if (tp->fc_bit && test_bit(tp->fc_bit,&netdev_fc_xoff)) - printk("BUG tx_timeout restarting rx when fc on\n"); -#endif + tulip_restart_rxtx(tp); /* Trigger an immediate transmit demand. */ outl(0, ioaddr + CSR1); @@ -742,7 +728,9 @@ unsigned long flags; del_timer_sync (&tp->timer); - +#ifdef CONFIG_TULIP_NAPI + del_timer_sync (&tp->oom_timer); +#endif spin_lock_irqsave (&tp->lock, flags); /* Disable interrupts by clearing the interrupt mask. */ @@ -781,13 +769,6 @@ netif_stop_queue (dev); -#ifdef CONFIG_NET_HW_FLOWCONTROL - if (tp->fc_bit) { - int bit = tp->fc_bit; - tp->fc_bit = 0; - netdev_unregister_fc(bit); - } -#endif tulip_down (dev); if (tulip_debug > 1) @@ -1629,10 +1610,17 @@ dev->hard_start_xmit = tulip_start_xmit; dev->tx_timeout = tulip_tx_timeout; dev->watchdog_timeo = TX_TIMEOUT; +#ifdef CONFIG_TULIP_NAPI + dev->poll = tulip_poll; + dev->weight = 16; +#endif dev->stop = tulip_close; dev->get_stats = tulip_get_stats; dev->do_ioctl = private_ioctl; dev->set_multicast_list = set_rx_mode; +#ifdef CONFIG_NET_POLL_CONTROLLER + dev->poll_controller = &poll_tulip; +#endif if (register_netdev(dev)) goto err_out_free_ring; @@ -1725,7 +1713,7 @@ pci_release_regions (pdev); err_out_free_netdev: - kfree (dev); + free_netdev (dev); return -ENODEV; } @@ -1789,6 +1777,22 @@ /* pci_power_off (pdev, -1); */ } +#ifdef CONFIG_NET_POLL_CONTROLLER +/* + * Polling 'interrupt' - used by things like netconsole to send skbs + * without having to re-enable interrupts. It's not called while + * the interrupt routine is executing. + */ + +static void poll_tulip (struct net_device *dev) +{ + /* disable_irq here is not very nice, but with the lockless + interrupt handler we have no other choice. */ + disable_irq(dev->irq); + tulip_interrupt (dev->irq, dev, NULL); + enable_irq(dev->irq); +} +#endif static struct pci_driver tulip_driver = { .name = DRV_NAME, diff -Nru a/drivers/net/tulip/winbond-840.c b/drivers/net/tulip/winbond-840.c --- a/drivers/net/tulip/winbond-840.c Thu Jan 22 18:59:24 2004 +++ b/drivers/net/tulip/winbond-840.c Thu Jan 22 18:59:24 2004 @@ -530,7 +530,7 @@ #endif pci_release_regions(pdev); err_out_netdev: - kfree (dev); + free_netdev (dev); return -ENODEV; } diff -Nru a/drivers/net/tulip/xircom_tulip_cb.c b/drivers/net/tulip/xircom_tulip_cb.c --- a/drivers/net/tulip/xircom_tulip_cb.c Thu Jan 22 18:59:24 2004 +++ b/drivers/net/tulip/xircom_tulip_cb.c Thu Jan 22 18:59:24 2004 @@ -648,8 +648,7 @@ pci_set_drvdata(pdev, NULL); pci_release_regions(pdev); err_out_free_netdev: - unregister_netdev(dev); - kfree(dev); + free_netdev(dev); return -ENODEV; } diff -Nru a/drivers/net/tun.c b/drivers/net/tun.c --- a/drivers/net/tun.c Thu Jan 22 18:59:25 2004 +++ b/drivers/net/tun.c Thu Jan 22 18:59:25 2004 @@ -118,12 +118,10 @@ } /* Initialize net device. */ -int tun_net_init(struct net_device *dev) +static void tun_net_init(struct net_device *dev) { struct tun_struct *tun = (struct tun_struct *)dev->priv; - DBG(KERN_INFO "%s: tun_net_init\n", tun->dev->name); - switch (tun->flags & TUN_TYPE_MASK) { case TUN_TUN_DEV: /* Point-to-Point TUN Device */ @@ -147,9 +145,7 @@ ether_setup(dev); break; - }; - - return 0; + } } /* Character device part */ @@ -351,7 +347,6 @@ init_waitqueue_head(&tun->read_wait); tun->owner = -1; - dev->init = tun_net_init; SET_MODULE_OWNER(dev); dev->open = tun_net_open; @@ -377,6 +372,7 @@ static int tun_set_iff(struct file *file, struct ifreq *ifr) { struct tun_struct *tun; + struct net_device *dev; int err; tun = tun_get_by_name(ifr->ifr_name); @@ -394,7 +390,6 @@ else { char *name; unsigned long flags = 0; - struct net_device *dev; err = -EINVAL; @@ -422,18 +417,17 @@ tun->dev = dev; tun->flags = flags; + tun_net_init(dev); + if (strchr(dev->name, '%')) { err = dev_alloc_name(dev, dev->name); - if (err < 0) { - kfree(dev); - goto failed; - } + if (err < 0) + goto err_free_dev; } - if ((err = register_netdevice(tun->dev))) { - kfree(dev); - goto failed; - } + err = register_netdevice(tun->dev); + if (err < 0) + goto err_free_dev; list_add(&tun->list, &tun_dev_list); } @@ -451,6 +445,9 @@ strcpy(ifr->ifr_name, tun->dev->name); return 0; + + err_free_dev: + free_netdev(dev); failed: return err; } diff -Nru a/drivers/net/via-rhine.c b/drivers/net/via-rhine.c --- a/drivers/net/via-rhine.c Thu Jan 22 18:59:27 2004 +++ b/drivers/net/via-rhine.c Thu Jan 22 18:59:27 2004 @@ -615,6 +615,15 @@ break; } +#ifdef CONFIG_NET_POLL_CONTROLLER +static void via_rhine_poll(struct net_device *dev) +{ + disable_irq(dev->irq); + via_rhine_interrupt(dev->irq, (void *)dev, NULL); + enable_irq(dev->irq); +} +#endif + static int __devinit via_rhine_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) { @@ -784,6 +793,9 @@ dev->ethtool_ops = &netdev_ethtool_ops; dev->tx_timeout = via_rhine_tx_timeout; dev->watchdog_timeo = TX_TIMEOUT; +#ifdef CONFIG_NET_POLL_CONTROLLER + dev->poll_controller = via_rhine_poll; +#endif if (np->drv_flags & ReqTxAlign) dev->features |= NETIF_F_SG|NETIF_F_HW_CSUM; diff -Nru a/drivers/net/wan/c101.c b/drivers/net/wan/c101.c --- a/drivers/net/wan/c101.c Thu Jan 22 18:59:26 2004 +++ b/drivers/net/wan/c101.c Thu Jan 22 18:59:26 2004 @@ -54,7 +54,7 @@ typedef struct card_s { - hdlc_device hdlc; /* HDLC device struct - must be first */ + struct net_device *dev; spinlock_t lock; /* TX lock */ u8 *win0base; /* ISA window base address */ u32 phy_winbase; /* ISA physical base address */ @@ -121,6 +121,7 @@ static void sca_msci_intr(port_t *port) { + struct net_device *dev = port_to_dev(port); card_t* card = port_to_card(port); u8 stat = sca_in(MSCI1_OFFSET + ST1, card); /* read MSCI ST1 status */ @@ -128,8 +129,9 @@ sca_out(stat & ST1_UDRN, MSCI0_OFFSET + ST1, card); if (stat & ST1_UDRN) { - port->hdlc.stats.tx_errors++; /* TX Underrun error detected */ - port->hdlc.stats.tx_fifo_errors++; + struct net_device_stats *stats = hdlc_stats(dev); + stats->tx_errors++; /* TX Underrun error detected */ + stats->tx_fifo_errors++; } /* Reset MSCI CDCD status bit - uses ch#2 DCD input */ @@ -137,7 +139,7 @@ if (stat & ST1_CDCD) hdlc_set_carrier(!(sca_in(MSCI1_OFFSET + ST3, card) & ST3_DCD), - &port->hdlc); + dev); } @@ -177,22 +179,21 @@ static int c101_open(struct net_device *dev) { - hdlc_device *hdlc = dev_to_hdlc(dev); - port_t *port = hdlc_to_port(hdlc); + port_t *port = dev_to_port(dev); int result; - result = hdlc_open(hdlc); + result = hdlc_open(dev); if (result) return result; writeb(1, port->win0base + C101_DTR); sca_out(0, MSCI1_OFFSET + CTL, port); /* RTS uses ch#2 output */ - sca_open(hdlc); + sca_open(dev); /* DCD is connected to port 2 !@#$%^& - disable MSCI0 CDCD interrupt */ sca_out(IE1_UDRN, MSCI0_OFFSET + IE1, port); sca_out(IE0_TXINT, MSCI0_OFFSET + IE0, port); - hdlc_set_carrier(!(sca_in(MSCI1_OFFSET + ST3, port) & ST3_DCD), hdlc); + hdlc_set_carrier(!(sca_in(MSCI1_OFFSET + ST3, port) & ST3_DCD), dev); printk(KERN_DEBUG "0x%X\n", sca_in(MSCI1_OFFSET + ST3, port)); /* enable MSCI1 CDCD interrupt */ @@ -206,13 +207,12 @@ static int c101_close(struct net_device *dev) { - hdlc_device *hdlc = dev_to_hdlc(dev); - port_t *port = hdlc_to_port(hdlc); + port_t *port = dev_to_port(dev); - sca_close(hdlc); + sca_close(dev); writeb(0, port->win0base + C101_DTR); sca_out(CTL_NORTS, MSCI1_OFFSET + CTL, port); - hdlc_close(hdlc); + hdlc_close(dev); return 0; } @@ -221,12 +221,11 @@ { const size_t size = sizeof(sync_serial_settings); sync_serial_settings new_line, *line = ifr->ifr_settings.ifs_ifsu.sync; - hdlc_device *hdlc = dev_to_hdlc(dev); - port_t *port = hdlc_to_port(hdlc); + port_t *port = dev_to_port(dev); #ifdef DEBUG_RINGS if (cmd == SIOCDEVPRIVATE) { - sca_dump_rings(hdlc); + sca_dump_rings(dev); printk(KERN_DEBUG "MSCI1: ST: %02x %02x %02x %02x\n", sca_in(MSCI1_OFFSET + ST0, port), sca_in(MSCI1_OFFSET + ST1, port), @@ -288,6 +287,8 @@ release_mem_region(card->phy_winbase, C101_MAPPED_RAM_SIZE); } + free_netdev(card->dev); + kfree(card); } @@ -296,6 +297,7 @@ static int __init c101_run(unsigned long irq, unsigned long winbase) { struct net_device *dev; + hdlc_device *hdlc; card_t *card; int result; @@ -316,6 +318,13 @@ } memset(card, 0, sizeof(card_t)); + card->dev = alloc_hdlcdev(card); + if (!card->dev) { + printk(KERN_ERR "c101: unable to allocate memory\n"); + kfree(card); + return -ENOBUFS; + } + if (request_irq(irq, sca_intr, 0, devname, card)) { printk(KERN_ERR "c101: could not allocate IRQ\n"); c101_destroy_card(card); @@ -347,7 +356,8 @@ sca_init(card, 0); - dev = hdlc_to_dev(&card->hdlc); + dev = port_to_dev(card); + hdlc = dev_to_hdlc(dev); spin_lock_init(&card->lock); SET_MODULE_OWNER(dev); @@ -358,24 +368,25 @@ dev->do_ioctl = c101_ioctl; dev->open = c101_open; dev->stop = c101_close; - card->hdlc.attach = sca_attach; - card->hdlc.xmit = sca_xmit; + hdlc->attach = sca_attach; + hdlc->xmit = sca_xmit; card->settings.clock_type = CLOCK_EXT; - result = register_hdlc_device(&card->hdlc); + result = register_hdlc_device(dev); if (result) { printk(KERN_WARNING "c101: unable to register hdlc device\n"); c101_destroy_card(card); return result; } + /* XXX: are we OK with having that done when card is already up? */ + sca_init_sync_port(card); /* Set up C101 memory */ - hdlc_set_carrier(!(sca_in(MSCI1_OFFSET + ST3, card) & ST3_DCD), - &card->hdlc); + hdlc_set_carrier(!(sca_in(MSCI1_OFFSET + ST3, card) & ST3_DCD), dev); printk(KERN_INFO "%s: Moxa C101 on IRQ%u," " using %u TX + %u RX packets rings\n", - hdlc_to_name(&card->hdlc), card->irq, + dev->name, card->irq, card->tx_ring_buffers, card->rx_ring_buffers); *new_card = card; @@ -424,7 +435,7 @@ while (card) { card_t *ptr = card; card = card->next_card; - unregister_hdlc_device(&ptr->hdlc); + unregister_hdlc_device(port_to_dev(ptr)); c101_destroy_card(ptr); } } diff -Nru a/drivers/net/wan/comx-proto-lapb.c b/drivers/net/wan/comx-proto-lapb.c --- a/drivers/net/wan/comx-proto-lapb.c Thu Jan 22 18:59:23 2004 +++ b/drivers/net/wan/comx-proto-lapb.c Thu Jan 22 18:59:23 2004 @@ -44,7 +44,7 @@ if (!dev || !dev->priv) { dev_kfree_skb(skb); } else { - lapb_data_received(dev->priv, skb); + lapb_data_received(dev, skb); } } @@ -82,7 +82,7 @@ return -ENODEV; } - err = lapb_connect_request(ch); + err = lapb_connect_request(dev); if (ch->debug_flags & DEBUG_COMX_LAPB) { comx_debug(dev, "%s: lapb opened, error code: %d\n", @@ -108,7 +108,7 @@ comx_debug(dev, "%s: lapb closed\n", dev->name); } - lapb_disconnect_request(ch); + lapb_disconnect_request(dev); ch->init_status &= ~LINE_OPEN; ch->line_status &= ~PROTO_UP; @@ -130,11 +130,11 @@ case 0x00: break; // transmit case 0x01: - lapb_connect_request(ch); + lapb_connect_request(dev); kfree_skb(skb); return 0; case 0x02: - lapb_disconnect_request(ch); + lapb_disconnect_request(dev); default: kfree_skb(skb); return 0; @@ -145,7 +145,7 @@ netif_stop_queue(dev); if ((skb2 = skb_clone(skb, GFP_ATOMIC)) != NULL) { - lapb_data_request(ch, skb2); + lapb_data_request(dev, skb2); } return FRAME_ACCEPTED; @@ -157,7 +157,7 @@ int len = 0; len += sprintf(page + len, "Line status: "); - if (lapb_getparms(dev->priv, &parms) != LAPB_OK) { + if (lapb_getparms(dev, &parms) != LAPB_OK) { len += sprintf(page + len, "not initialized\n"); return len; } @@ -178,7 +178,7 @@ struct lapb_parms_struct parms; int len = 0; - if (lapb_getparms(dev->priv, &parms)) { + if (lapb_getparms(dev, &parms)) { return -ENODEV; } @@ -223,7 +223,7 @@ unsigned long parm; char *page; - if (lapb_getparms(dev->priv, &parms)) { + if (lapb_getparms(dev, &parms)) { return -ENODEV; } @@ -243,23 +243,23 @@ parm=simple_strtoul(page,NULL,10); if (parm > 0 && parm < 100) { parms.t1=parm; - lapb_setparms(dev->priv, &parms); + lapb_setparms(dev, &parms); } } else if (strcmp(entry->name, FILENAME_T2) == 0) { parm=simple_strtoul(page, NULL, 10); if (parm > 0 && parm < 100) { parms.t2=parm; - lapb_setparms(dev->priv, &parms); + lapb_setparms(dev, &parms); } } else if (strcmp(entry->name, FILENAME_N2) == 0) { parm=simple_strtoul(page, NULL, 10); if (parm > 0 && parm < 100) { parms.n2=parm; - lapb_setparms(dev->priv, &parms); + lapb_setparms(dev, &parms); } } else if (strcmp(entry->name, FILENAME_WINDOW) == 0) { parms.window = simple_strtoul(page, NULL, 10); - lapb_setparms(dev->priv, &parms); + lapb_setparms(dev, &parms); } else if (strcmp(entry->name, FILENAME_MODE) == 0) { if (comx_strcasecmp(page, "dte") == 0) { parms.mode &= ~(LAPB_DCE | LAPB_DTE); @@ -276,7 +276,7 @@ parms.mode &= ~LAPB_STANDARD; parms.mode |= LAPB_EXTENDED; } - lapb_setparms(dev->priv, &parms); + lapb_setparms(dev, &parms); } else { printk(KERN_ERR "comxlapb_write_proc: internal error, filename %s\n", entry->name); @@ -287,9 +287,9 @@ return count; } -static void comxlapb_connected(void *token, int reason) +static void comxlapb_connected(struct net_device *dev, int reason) { - struct comx_channel *ch = token; + struct comx_channel *ch = dev->priv; struct proc_dir_entry *comxdir = ch->procdir->subdir; if (ch->debug_flags & DEBUG_COMX_LAPB) { @@ -327,9 +327,9 @@ comx_status(ch->dev, ch->line_status); } -static void comxlapb_disconnected(void *token, int reason) +static void comxlapb_disconnected(struct net_device *dev, int reason) { - struct comx_channel *ch = token; + struct comx_channel *ch = dev->priv; struct proc_dir_entry *comxdir = ch->procdir->subdir; if (ch->debug_flags & DEBUG_COMX_LAPB) { @@ -366,9 +366,9 @@ comx_status(ch->dev, ch->line_status); } -static int comxlapb_data_indication(void *token, struct sk_buff *skb) +static int comxlapb_data_indication(struct net_device *dev, struct sk_buff *skb) { - struct comx_channel *ch = token; + struct comx_channel *ch = dev->priv; if (ch->dev->type == ARPHRD_X25) { skb_push(skb, 1); @@ -387,9 +387,9 @@ return comx_rx(ch->dev, skb); } -static void comxlapb_data_transmit(void *token, struct sk_buff *skb) +static void comxlapb_data_transmit(struct net_device *dev, struct sk_buff *skb) { - struct comx_channel *ch = token; + struct comx_channel *ch = dev->priv; if (ch->HW_send_packet) { ch->HW_send_packet(ch->dev, skb); @@ -417,7 +417,7 @@ if (ch->debug_flags & DEBUG_COMX_LAPB) { comx_debug(dev, "%s: unregistering lapb\n", dev->name); } - lapb_unregister(dev->priv); + lapb_unregister(dev); remove_proc_entry(FILENAME_T1, ch->procdir); remove_proc_entry(FILENAME_T2, ch->procdir); @@ -453,7 +453,7 @@ lapbreg.disconnect_indication = comxlapb_disconnected; lapbreg.data_indication = comxlapb_data_indication; lapbreg.data_transmit = comxlapb_data_transmit; - if (lapb_register(dev->priv, &lapbreg)) { + if (lapb_register(dev, &lapbreg)) { return -ENOMEM; } if (ch->debug_flags & DEBUG_COMX_LAPB) { diff -Nru a/drivers/net/wan/cosa.c b/drivers/net/wan/cosa.c --- a/drivers/net/wan/cosa.c Thu Jan 22 18:59:23 2004 +++ b/drivers/net/wan/cosa.c Thu Jan 22 18:59:23 2004 @@ -594,40 +594,47 @@ /*---------- SPPP/HDLC netdevice ---------- */ +static void cosa_setup(struct net_device *d) +{ + d->open = cosa_sppp_open; + d->stop = cosa_sppp_close; + d->hard_start_xmit = cosa_sppp_tx; + d->do_ioctl = cosa_sppp_ioctl; + d->get_stats = cosa_net_stats; + d->tx_timeout = cosa_sppp_timeout; + d->watchdog_timeo = TX_TIMEOUT; +} + static void sppp_channel_init(struct channel_data *chan) { struct net_device *d; chan->if_ptr = &chan->pppdev; - chan->pppdev.dev = kmalloc(sizeof(struct net_device), GFP_KERNEL); - memset(chan->pppdev.dev, 0, sizeof(struct net_device)); + d = alloc_netdev(0, chan->name, cosa_setup); + if (!d) { + printk(KERN_WARNING "%s: alloc_netdev failed.\n", chan->name); + return; + } + chan->pppdev.dev = d; sppp_attach(&chan->pppdev); - d=chan->pppdev.dev; - strcpy(d->name, chan->name); d->base_addr = chan->cosa->datareg; d->irq = chan->cosa->irq; d->dma = chan->cosa->dma; d->priv = chan; - d->init = NULL; - d->open = cosa_sppp_open; - d->stop = cosa_sppp_close; - d->hard_start_xmit = cosa_sppp_tx; - d->do_ioctl = cosa_sppp_ioctl; - d->get_stats = cosa_net_stats; - d->tx_timeout = cosa_sppp_timeout; - d->watchdog_timeo = TX_TIMEOUT; if (register_netdev(d)) { printk(KERN_WARNING "%s: register_netdev failed.\n", d->name); - sppp_detach(chan->pppdev.dev); - free_netdev(chan->pppdev.dev); + sppp_detach(d); + free_netdev(d); + chan->pppdev.dev = NULL; return; } } static void sppp_channel_delete(struct channel_data *chan) { - sppp_detach(chan->pppdev.dev); unregister_netdev(chan->pppdev.dev); + sppp_detach(chan->pppdev.dev); free_netdev(chan->pppdev.dev); + chan->pppdev.dev = NULL; } static int cosa_sppp_open(struct net_device *d) diff -Nru a/drivers/net/wan/dlci.c b/drivers/net/wan/dlci.c --- a/drivers/net/wan/dlci.c Thu Jan 22 18:59:25 2004 +++ b/drivers/net/wan/dlci.c Thu Jan 22 18:59:25 2004 @@ -414,7 +414,7 @@ err2: rtnl_unlock(); - kfree(master); + free_netdev(master); err1: dev_put(slave); return(err); diff -Nru a/drivers/net/wan/dscc4.c b/drivers/net/wan/dscc4.c --- a/drivers/net/wan/dscc4.c Thu Jan 22 18:59:24 2004 +++ b/drivers/net/wan/dscc4.c Thu Jan 22 18:59:24 2004 @@ -228,7 +228,7 @@ unsigned short encoding; unsigned short parity; - hdlc_device hdlc; + struct net_device *dev; sync_serial_settings settings; u32 __pad __attribute__ ((aligned (4))); }; @@ -364,7 +364,7 @@ static void dscc4_timer(unsigned long); static void dscc4_tx_timeout(struct net_device *); static irqreturn_t dscc4_irq(int irq, void *dev_id, struct pt_regs *ptregs); -static int dscc4_hdlc_attach(hdlc_device *, unsigned short, unsigned short); +static int dscc4_hdlc_attach(struct net_device *, unsigned short, unsigned short); static int dscc4_set_iface(struct dscc4_dev_priv *, struct net_device *); static inline int dscc4_set_quartz(struct dscc4_dev_priv *, int); #ifdef DSCC4_POLLING @@ -373,7 +373,12 @@ static inline struct dscc4_dev_priv *dscc4_priv(struct net_device *dev) { - return list_entry(dev, struct dscc4_dev_priv, hdlc.netdev); + return dev_to_hdlc(dev)->priv; +} + +static inline struct net_device *dscc4_to_dev(struct dscc4_dev_priv *p) +{ + return p->dev; } static void scc_patchl(u32 mask, u32 value, struct dscc4_dev_priv *dpriv, @@ -636,7 +641,7 @@ struct net_device *dev) { struct RxFD *rx_fd = dpriv->rx_fd + dpriv->rx_current%RX_RING_SIZE; - struct net_device_stats *stats = &dpriv->hdlc.stats; + struct net_device_stats *stats = hdlc_stats(dev); struct pci_dev *pdev = dpriv->pci_priv->pdev; struct sk_buff *skb; int pkt_len; @@ -689,10 +694,12 @@ root = ppriv->root; for (i = 0; i < dev_per_card; i++) - unregister_hdlc_device(&root[i].hdlc); + unregister_hdlc_device(dscc4_to_dev(&root[i])); pci_set_drvdata(pdev, NULL); + for (i = 0; i < dev_per_card; i++) + free_netdev(root[i].dev); kfree(root); kfree(ppriv); } @@ -874,17 +881,31 @@ } memset(root, 0, dev_per_card*sizeof(*root)); + for (i = 0; i < dev_per_card; i++) { + root[i].dev = alloc_hdlcdev(root + i); + if (!root[i].dev) { + while (i--) + free_netdev(root[i].dev); + goto err_free_dev; + } + } + ppriv = (struct dscc4_pci_priv *) kmalloc(sizeof(*ppriv), GFP_KERNEL); if (!ppriv) { printk(KERN_ERR "%s: can't allocate private data\n", DRV_NAME); - goto err_free_dev; + goto err_free_dev2; } memset(ppriv, 0, sizeof(struct dscc4_pci_priv)); + ret = dscc4_set_quartz(root, quartz); + if (ret < 0) + goto err_free_priv; + ppriv->root = root; + spin_lock_init(&ppriv->lock); for (i = 0; i < dev_per_card; i++) { struct dscc4_dev_priv *dpriv = root + i; - hdlc_device *hdlc = &dpriv->hdlc; - struct net_device *d = hdlc_to_dev(hdlc); + struct net_device *d = dscc4_to_dev(dpriv); + hdlc_device *hdlc = dev_to_hdlc(d); d->base_addr = ioaddr; d->init = NULL; @@ -905,36 +926,34 @@ hdlc->xmit = dscc4_start_xmit; hdlc->attach = dscc4_hdlc_attach; - ret = register_hdlc_device(hdlc); - if (ret < 0) { - printk(KERN_ERR "%s: unable to register\n", DRV_NAME); - goto err_unregister; - } - dscc4_init_registers(dpriv, d); dpriv->parity = PARITY_CRC16_PR0_CCITT; dpriv->encoding = ENCODING_NRZ; - + ret = dscc4_init_ring(d); + if (ret < 0) + goto err_unregister; + + ret = register_hdlc_device(d); if (ret < 0) { - unregister_hdlc_device(hdlc); + printk(KERN_ERR "%s: unable to register\n", DRV_NAME); + dscc4_release_ring(dpriv); goto err_unregister; - } + } } - ret = dscc4_set_quartz(root, quartz); - if (ret < 0) - goto err_unregister; - ppriv->root = root; - spin_lock_init(&ppriv->lock); pci_set_drvdata(pdev, ppriv); return ret; err_unregister: while (--i >= 0) { dscc4_release_ring(root + i); - unregister_hdlc_device(&root[i].hdlc); + unregister_hdlc_device(dscc4_to_dev(&root[i])); } +err_free_priv: kfree(ppriv); +err_free_dev2: + for (i = 0; i < dev_per_card; i++) + free_netdev(root[i].dev); err_free_dev: kfree(root); err_out: @@ -964,7 +983,7 @@ sync_serial_settings *settings = &dpriv->settings; if (settings->loopback && (settings->clock_type != CLOCK_INT)) { - struct net_device *dev = hdlc_to_dev(&dpriv->hdlc); + struct net_device *dev = dscc4_to_dev(dpriv); printk(KERN_INFO "%s: loopback requires clock\n", dev->name); return -1; @@ -1015,14 +1034,13 @@ static int dscc4_open(struct net_device *dev) { struct dscc4_dev_priv *dpriv = dscc4_priv(dev); - hdlc_device *hdlc = &dpriv->hdlc; struct dscc4_pci_priv *ppriv; int ret = -EAGAIN; if ((dscc4_loopback_check(dpriv) < 0) || !dev->hard_start_xmit) goto err; - if ((ret = hdlc_open(hdlc))) + if ((ret = hdlc_open(dev))) goto err; ppriv = dpriv->pci_priv; @@ -1103,7 +1121,7 @@ scc_writel(0xffffffff, dpriv, dev, IMR); scc_patchl(PowerUp | Vis, 0, dpriv, dev, CCR0); err_out: - hdlc_close(hdlc); + hdlc_close(dev); err: return ret; } @@ -1155,7 +1173,6 @@ static int dscc4_close(struct net_device *dev) { struct dscc4_dev_priv *dpriv = dscc4_priv(dev); - hdlc_device *hdlc = dev_to_hdlc(dev); del_timer_sync(&dpriv->timer); netif_stop_queue(dev); @@ -1166,7 +1183,7 @@ dpriv->flags |= FakeReset; - hdlc_close(hdlc); + hdlc_close(dev); return 0; } @@ -1467,7 +1484,7 @@ int i, handled = 1; priv = root->pci_priv; - dev = hdlc_to_dev(&root->hdlc); + dev = dscc4_to_dev(root); spin_lock_irqsave(&priv->lock, flags); @@ -1518,7 +1535,7 @@ static inline void dscc4_tx_irq(struct dscc4_pci_priv *ppriv, struct dscc4_dev_priv *dpriv) { - struct net_device *dev = hdlc_to_dev(&dpriv->hdlc); + struct net_device *dev = dscc4_to_dev(dpriv); u32 state; int cur, loop = 0; @@ -1549,7 +1566,7 @@ if (state & SccEvt) { if (state & Alls) { - struct net_device_stats *stats = &dpriv->hdlc.stats; + struct net_device_stats *stats = hdlc_stats(dev); struct sk_buff *skb; struct TxFD *tx_fd; @@ -1677,7 +1694,7 @@ } if (state & Err) { printk(KERN_INFO "%s: Tx ERR\n", dev->name); - dev_to_hdlc(dev)->stats.tx_errors++; + hdlc_stats(dev)->tx_errors++; state &= ~Err; } } @@ -1687,7 +1704,7 @@ static inline void dscc4_rx_irq(struct dscc4_pci_priv *priv, struct dscc4_dev_priv *dpriv) { - struct net_device *dev = hdlc_to_dev(&dpriv->hdlc); + struct net_device *dev = dscc4_to_dev(dpriv); u32 state; int cur; @@ -1813,7 +1830,7 @@ if (!(rx_fd->state2 & DataComplete)) break; if (rx_fd->state2 & FrameAborted) { - dev_to_hdlc(dev)->stats.rx_over_errors++; + hdlc_stats(dev)->rx_over_errors++; rx_fd->state1 |= Hold; rx_fd->state2 = 0x00000000; rx_fd->end = 0xbabeface; @@ -1961,7 +1978,7 @@ ppriv = pci_get_drvdata(pdev); root = ppriv->root; - ioaddr = hdlc_to_dev(&root->hdlc)->base_addr; + ioaddr = dscc4_to_dev(root)->base_addr; dscc4_pci_reset(pdev, ioaddr); @@ -1988,10 +2005,9 @@ pci_resource_len(pdev, 0)); } -static int dscc4_hdlc_attach(hdlc_device *hdlc, unsigned short encoding, +static int dscc4_hdlc_attach(struct net_device *dev, unsigned short encoding, unsigned short parity) { - struct net_device *dev = hdlc_to_dev(hdlc); struct dscc4_dev_priv *dpriv = dscc4_priv(dev); if (encoding != ENCODING_NRZ && diff -Nru a/drivers/net/wan/farsync.c b/drivers/net/wan/farsync.c --- a/drivers/net/wan/farsync.c Thu Jan 22 18:59:26 2004 +++ b/drivers/net/wan/farsync.c Thu Jan 22 18:59:26 2004 @@ -328,7 +328,7 @@ /* Per port (line or channel) information */ struct fst_port_info { - hdlc_device hdlc; /* HDLC device struct - must be first */ + struct net_device *dev; struct fst_card_info *card; /* Card we're associated with */ int index; /* Port index on the card */ int hwif; /* Line hardware (lineInterface copy) */ @@ -357,9 +357,8 @@ }; /* Convert an HDLC device pointer into a port info pointer and similar */ -#define hdlc_to_port(H) ((struct fst_port_info *)(H)) -#define dev_to_port(D) hdlc_to_port(dev_to_hdlc(D)) -#define port_to_dev(P) hdlc_to_dev(&(P)->hdlc) +#define dev_to_port(D) (dev_to_hdlc(D)->priv) +#define port_to_dev(P) ((P)->dev) /* @@ -651,6 +650,8 @@ int rxp; unsigned short len; struct sk_buff *skb; + struct net_device *dev = port_to_dev(port); + struct net_device_stats *stats = hdlc_stats(dev); int i; @@ -678,24 +679,24 @@ len ); if ( dmabits != ( RX_STP | RX_ENP ) || len > LEN_RX_BUFFER - 2 ) { - port->hdlc.stats.rx_errors++; + stats->rx_errors++; /* Update error stats and discard buffer */ if ( dmabits & RX_OFLO ) { - port->hdlc.stats.rx_fifo_errors++; + stats->rx_fifo_errors++; } if ( dmabits & RX_CRC ) { - port->hdlc.stats.rx_crc_errors++; + stats->rx_crc_errors++; } if ( dmabits & RX_FRAM ) { - port->hdlc.stats.rx_frame_errors++; + stats->rx_frame_errors++; } if ( dmabits == ( RX_STP | RX_ENP )) { - port->hdlc.stats.rx_length_errors++; + stats->rx_length_errors++; } /* Discard buffer descriptors until we see the end of packet @@ -732,7 +733,7 @@ { dbg ( DBG_RX,"intr_rx: can't allocate buffer\n"); - port->hdlc.stats.rx_dropped++; + stats->rx_dropped++; /* Return descriptor to card */ FST_WRB ( card, rxDescrRing[pi][rxp].bits, DMA_OWN ); @@ -756,16 +757,16 @@ port->rxpos = rxp; /* Update stats */ - port->hdlc.stats.rx_packets++; - port->hdlc.stats.rx_bytes += len; + stats->rx_packets++; + stats->rx_bytes += len; /* Push upstream */ skb->mac.raw = skb->data; - skb->dev = hdlc_to_dev ( &port->hdlc ); + skb->dev = dev; skb->protocol = hdlc_type_trans(skb, skb->dev); netif_rx ( skb ); - port_to_dev ( port )->last_rx = jiffies; + dev->last_rx = jiffies; } @@ -835,8 +836,8 @@ * always load up the entire packet for DMA. */ dbg ( DBG_TX,"Tx underflow port %d\n", event & 0x03 ); - port->hdlc.stats.tx_errors++; - port->hdlc.stats.tx_fifo_errors++; + hdlc_stats(port_to_dev(port))->tx_errors++; + hdlc_stats(port_to_dev(port))->tx_fifo_errors++; break; case INIT_CPLT: @@ -1309,7 +1310,7 @@ { int err; - err = hdlc_open ( dev_to_hdlc ( dev )); + err = hdlc_open (dev); if ( err ) return err; @@ -1323,12 +1324,12 @@ { netif_stop_queue ( dev ); fst_closeport ( dev_to_port ( dev )); - hdlc_close ( dev_to_hdlc ( dev )); + hdlc_close ( dev ); return 0; } static int -fst_attach ( hdlc_device *hdlc, unsigned short encoding, unsigned short parity ) +fst_attach ( struct net_device *dev, unsigned short encoding, unsigned short parity ) { /* Setting currently fixed in FarSync card so we check and forget */ if ( encoding != ENCODING_NRZ || parity != PARITY_CRC16_PR1_CCITT ) @@ -1341,13 +1342,14 @@ fst_tx_timeout ( struct net_device *dev ) { struct fst_port_info *port; + struct net_device_stats *stats = hdlc_stats(dev); dbg ( DBG_INTR | DBG_TX,"tx_timeout\n"); port = dev_to_port ( dev ); - port->hdlc.stats.tx_errors++; - port->hdlc.stats.tx_aborted_errors++; + stats->tx_errors++; + stats->tx_aborted_errors++; if ( port->txcnt > 0 ) fst_issue_cmd ( port, ABORTTX ); @@ -1360,6 +1362,7 @@ static int fst_start_xmit ( struct sk_buff *skb, struct net_device *dev ) { + struct net_device_stats *stats = hdlc_stats(dev); struct fst_card_info *card; struct fst_port_info *port; unsigned char dmabits; @@ -1374,8 +1377,8 @@ if ( ! netif_carrier_ok ( dev )) { dev_kfree_skb ( skb ); - port->hdlc.stats.tx_errors++; - port->hdlc.stats.tx_carrier_errors++; + stats->tx_errors++; + stats->tx_carrier_errors++; return 0; } @@ -1385,7 +1388,7 @@ dbg ( DBG_TX,"Packet too large %d vs %d\n", skb->len, LEN_TX_BUFFER ); dev_kfree_skb ( skb ); - port->hdlc.stats.tx_errors++; + stats->tx_errors++; return 0; } @@ -1399,7 +1402,7 @@ spin_unlock_irqrestore ( &card->card_lock, flags ); dbg ( DBG_TX,"Out of Tx buffers\n"); dev_kfree_skb ( skb ); - port->hdlc.stats.tx_errors++; + stats->tx_errors++; return 0; } if ( ++port->txpos >= NUM_TX_BUFFER ) @@ -1419,8 +1422,8 @@ FST_WRW ( card, txDescrRing[pi][txp].bcnt, cnv_bcnt ( skb->len )); FST_WRB ( card, txDescrRing[pi][txp].bits, DMA_OWN | TX_STP | TX_ENP ); - port->hdlc.stats.tx_packets++; - port->hdlc.stats.tx_bytes += skb->len; + stats->tx_packets++; + stats->tx_bytes += skb->len; dev_kfree_skb ( skb ); @@ -1447,55 +1450,29 @@ { int i; int err; - struct net_device *dev; /* We're working on a number of ports based on the card ID. If the * firmware detects something different later (should never happen) * we'll have to revise it in some way then. */ - for ( i = 0 ; i < card->nports ; i++ ) - { - card->ports[i].card = card; - card->ports[i].index = i; - card->ports[i].run = 0; - - dev = hdlc_to_dev ( &card->ports[i].hdlc ); - - /* Fill in the net device info */ - /* Since this is a PCI setup this is purely - * informational. Give them the buffer addresses - * and basic card I/O. - */ - dev->mem_start = card->phys_mem - + BUF_OFFSET ( txBuffer[i][0][0]); - dev->mem_end = card->phys_mem - + BUF_OFFSET ( txBuffer[i][NUM_TX_BUFFER][0]); - dev->base_addr = card->pci_conf; - dev->irq = card->irq; - - dev->tx_queue_len = FST_TX_QUEUE_LEN; - dev->open = fst_open; - dev->stop = fst_close; - dev->do_ioctl = fst_ioctl; - dev->watchdog_timeo = FST_TX_TIMEOUT; - dev->tx_timeout = fst_tx_timeout; - card->ports[i].hdlc.attach = fst_attach; - card->ports[i].hdlc.xmit = fst_start_xmit; - - if (( err = register_hdlc_device ( &card->ports[i].hdlc )) < 0 ) - { + for ( i = 0 ; i < card->nports ; i++ ) { + err = register_hdlc_device(card->ports[i].dev); + if (err < 0) { + int j; printk_err ("Cannot register HDLC device for port %d" " (errno %d)\n", i, -err ); + for (j = i; j < card->nports; j++) { + free_netdev(card->ports[j].dev); + card->ports[j].dev = NULL; + } card->nports = i; break; } } - spin_lock_init ( &card->card_lock ); - printk ( KERN_INFO "%s-%s: %s IRQ%d, %d ports\n", - hdlc_to_dev(&card->ports[0].hdlc)->name, - hdlc_to_dev(&card->ports[card->nports-1].hdlc)->name, + port_to_dev(&card->ports[0])->name, + port_to_dev(&card->ports[card->nports-1])->name, type_strings[card->type], card->irq, card->nports ); } @@ -1510,6 +1487,7 @@ static int firsttime_done = 0; struct fst_card_info *card; int err = 0; + int i; if ( ! firsttime_done ) { @@ -1546,6 +1524,46 @@ card->state = FST_UNINIT; + spin_lock_init ( &card->card_lock ); + + for ( i = 0 ; i < card->nports ; i++ ) { + struct net_device *dev = alloc_hdlcdev(&card->ports[i]); + hdlc_device *hdlc; + if (!dev) { + while (i--) + free_netdev(card->ports[i].dev); + printk_err ("FarSync: out of memory\n"); + goto error_free_card; + } + card->ports[i].dev = dev; + card->ports[i].card = card; + card->ports[i].index = i; + card->ports[i].run = 0; + + hdlc = dev_to_hdlc(dev); + + /* Fill in the net device info */ + /* Since this is a PCI setup this is purely + * informational. Give them the buffer addresses + * and basic card I/O. + */ + dev->mem_start = card->phys_mem + + BUF_OFFSET ( txBuffer[i][0][0]); + dev->mem_end = card->phys_mem + + BUF_OFFSET ( txBuffer[i][NUM_TX_BUFFER][0]); + dev->base_addr = card->pci_conf; + dev->irq = card->irq; + + dev->tx_queue_len = FST_TX_QUEUE_LEN; + dev->open = fst_open; + dev->stop = fst_close; + dev->do_ioctl = fst_ioctl; + dev->watchdog_timeo = FST_TX_TIMEOUT; + dev->tx_timeout = fst_tx_timeout; + hdlc->attach = fst_attach; + hdlc->xmit = fst_start_xmit; + } + dbg ( DBG_PCI,"type %d nports %d irq %d\n", card->type, card->nports, card->irq ); dbg ( DBG_PCI,"conf %04x mem %08x ctlmem %08x\n", @@ -1557,7 +1575,7 @@ printk_err ("Unable to get config I/O @ 0x%04X\n", card->pci_conf ); err = -ENODEV; - goto error_free_card; + goto error_free_ports; } if ( ! request_mem_region ( card->phys_mem, FST_MEMSIZE,"Shared RAM")) { @@ -1628,6 +1646,9 @@ error_release_io: release_region ( card->pci_conf, 0x80 ); +error_free_ports: + for (i = 0; i < card->nports; i++) + free_netdev(card->ports[i].dev); error_free_card: kfree ( card ); return err; @@ -1647,7 +1668,8 @@ for ( i = 0 ; i < card->nports ; i++ ) { - unregister_hdlc_device ( &card->ports[i].hdlc ); + struct net_device *dev = port_to_dev(&card->ports[i]); + unregister_hdlc_device(dev); } fst_disable_intr ( card ); @@ -1659,6 +1681,9 @@ release_mem_region ( card->phys_ctlmem, 0x10 ); release_mem_region ( card->phys_mem, FST_MEMSIZE ); release_region ( card->pci_conf, 0x80 ); + + for (i = 0; i < card->nports; i++) + free_netdev(card->ports[i].dev); kfree ( card ); } diff -Nru a/drivers/net/wan/hd6457x.c b/drivers/net/wan/hd6457x.c --- a/drivers/net/wan/hd6457x.c Thu Jan 22 18:59:24 2004 +++ b/drivers/net/wan/hd6457x.c Thu Jan 22 18:59:24 2004 @@ -73,6 +73,11 @@ #define writea(value, ptr) writel(value, ptr) #endif +static inline struct net_device *port_to_dev(port_t *port) +{ + return port->dev; +} + static inline int sca_intr_status(card_t *card) { u8 result = 0; @@ -110,22 +115,11 @@ return result; } - - -static inline port_t* hdlc_to_port(hdlc_device *hdlc) -{ - return (port_t*)hdlc; -} - - - static inline port_t* dev_to_port(struct net_device *dev) { - return hdlc_to_port(dev_to_hdlc(dev)); + return dev_to_hdlc(dev)->priv; } - - static inline u16 next_desc(port_t *port, u16 desc, int transmit) { return (desc + 1) % (transmit ? port_to_card(port)->tx_ring_buffers @@ -245,7 +239,7 @@ } hdlc_set_carrier(!(sca_in(get_msci(port) + ST3, card) & ST3_DCD), - &port->hdlc); + port_to_dev(port)); } @@ -262,13 +256,14 @@ sca_out(stat & (ST1_UDRN | ST1_CDCD), msci + ST1, card); if (stat & ST1_UDRN) { - port->hdlc.stats.tx_errors++; /* TX Underrun error detected */ - port->hdlc.stats.tx_fifo_errors++; + struct net_device_stats *stats = hdlc_stats(port_to_dev(port)); + stats->tx_errors++; /* TX Underrun error detected */ + stats->tx_fifo_errors++; } if (stat & ST1_CDCD) hdlc_set_carrier(!(sca_in(msci + ST3, card) & ST3_DCD), - &port->hdlc); + port_to_dev(port)); } #endif @@ -276,6 +271,8 @@ static inline void sca_rx(card_t *card, port_t *port, pkt_desc *desc, u16 rxin) { + struct net_device *dev = port_to_dev(port); + struct net_device_stats *stats = hdlc_stats(dev); struct sk_buff *skb; u16 len; u32 buff; @@ -287,7 +284,7 @@ len = readw(&desc->len); skb = dev_alloc_skb(len); if (!skb) { - port->hdlc.stats.rx_dropped++; + stats->rx_dropped++; return; } @@ -313,15 +310,15 @@ #endif skb_put(skb, len); #ifdef DEBUG_PKT - printk(KERN_DEBUG "%s RX(%i):", hdlc_to_name(&port->hdlc), skb->len); + printk(KERN_DEBUG "%s RX(%i):", dev->name, skb->len); debug_frame(skb); #endif - port->hdlc.stats.rx_packets++; - port->hdlc.stats.rx_bytes += skb->len; + stats->rx_packets++; + stats->rx_bytes += skb->len; skb->mac.raw = skb->data; - skb->dev = hdlc_to_dev(&port->hdlc); + skb->dev = dev; skb->dev->last_rx = jiffies; - skb->protocol = hdlc_type_trans(skb, hdlc_to_dev(&port->hdlc)); + skb->protocol = hdlc_type_trans(skb, dev); netif_rx(skb); } @@ -333,7 +330,7 @@ u16 dmac = get_dmac_rx(port); card_t *card = port_to_card(port); u8 stat = sca_in(DSR_RX(phy_node(port)), card); /* read DMA Status */ - struct net_device_stats *stats = &port->hdlc.stats; + struct net_device_stats *stats = hdlc_stats(port_to_dev(port)); /* Reset DSR status bits */ sca_out((stat & (DSR_EOT | DSR_EOM | DSR_BOF | DSR_COF)) | DSR_DWE, @@ -380,6 +377,8 @@ /* Transmit DMA interrupt service */ static inline void sca_tx_intr(port_t *port) { + struct net_device *dev = port_to_dev(port); + struct net_device_stats *stats = hdlc_stats(dev); u16 dmac = get_dmac_tx(port); card_t* card = port_to_card(port); u8 stat; @@ -401,13 +400,13 @@ break; /* Transmitter is/will_be sending this frame */ desc = desc_address(port, port->txlast, 1); - port->hdlc.stats.tx_packets++; - port->hdlc.stats.tx_bytes += readw(&desc->len); + stats->tx_packets++; + stats->tx_bytes += readw(&desc->len); writeb(0, &desc->stat); /* Free descriptor */ port->txlast = next_desc(port, port->txlast, 1); } - netif_wake_queue(hdlc_to_dev(&port->hdlc)); + netif_wake_queue(dev); spin_unlock(&port->lock); } @@ -508,9 +507,9 @@ -static void sca_open(hdlc_device *hdlc) +static void sca_open(struct net_device *dev) { - port_t *port = hdlc_to_port(hdlc); + port_t *port = dev_to_port(dev); card_t* card = port_to_card(port); u16 msci = get_msci(port); u8 md0, md2; @@ -569,7 +568,7 @@ - all DMA interrupts */ - hdlc_set_carrier(!(sca_in(msci + ST3, card) & ST3_DCD), hdlc); + hdlc_set_carrier(!(sca_in(msci + ST3, card) & ST3_DCD), dev); #ifdef __HD64570_H /* MSCI TX INT and RX INT A IRQ enable */ @@ -600,18 +599,18 @@ sca_out(CMD_TX_ENABLE, msci + CMD, card); sca_out(CMD_RX_ENABLE, msci + CMD, card); - netif_start_queue(hdlc_to_dev(hdlc)); + netif_start_queue(dev); } -static void sca_close(hdlc_device *hdlc) +static void sca_close(struct net_device *dev) { - port_t *port = hdlc_to_port(hdlc); + port_t *port = dev_to_port(dev); card_t* card = port_to_card(port); /* reset channel */ - netif_stop_queue(hdlc_to_dev(hdlc)); + netif_stop_queue(dev); sca_out(CMD_RESET, get_msci(port) + CMD, port_to_card(port)); #ifdef __HD64570_H /* disable MSCI interrupts */ @@ -629,7 +628,7 @@ -static int sca_attach(hdlc_device *hdlc, unsigned short encoding, +static int sca_attach(struct net_device *dev, unsigned short encoding, unsigned short parity) { if (encoding != ENCODING_NRZ && @@ -650,17 +649,17 @@ parity != PARITY_CRC16_PR1_CCITT) return -EINVAL; - hdlc_to_port(hdlc)->encoding = encoding; - hdlc_to_port(hdlc)->parity = parity; + dev_to_port(dev)->encoding = encoding; + dev_to_port(dev)->parity = parity; return 0; } #ifdef DEBUG_RINGS -static void sca_dump_rings(hdlc_device *hdlc) +static void sca_dump_rings(struct net_device *dev) { - port_t *port = hdlc_to_port(hdlc); + port_t *port = dev_to_port(dev); card_t *card = port_to_card(port); u16 cnt; #if !defined(PAGE0_ALWAYS_MAPPED) && !defined(ALL_PAGES_ALWAYS_MAPPED) @@ -729,8 +728,7 @@ static int sca_xmit(struct sk_buff *skb, struct net_device *dev) { - hdlc_device *hdlc = dev_to_hdlc(dev); - port_t *port = hdlc_to_port(hdlc); + port_t *port = dev_to_port(dev); card_t *card = port_to_card(port); pkt_desc *desc; u32 buff, len; @@ -753,7 +751,7 @@ } #ifdef DEBUG_PKT - printk(KERN_DEBUG "%s TX(%i):", hdlc_to_name(hdlc), skb->len); + printk(KERN_DEBUG "%s TX(%i):", dev->name, skb->len); debug_frame(skb); #endif @@ -790,7 +788,7 @@ desc = desc_address(port, port->txin + 1, 1); if (readb(&desc->stat)) /* allow 1 packet gap */ - netif_stop_queue(hdlc_to_dev(&port->hdlc)); + netif_stop_queue(dev); spin_unlock_irq(&port->lock); diff -Nru a/drivers/net/wan/hdlc_cisco.c b/drivers/net/wan/hdlc_cisco.c --- a/drivers/net/wan/hdlc_cisco.c Thu Jan 22 18:59:24 2004 +++ b/drivers/net/wan/hdlc_cisco.c Thu Jan 22 18:59:24 2004 @@ -57,7 +57,7 @@ -static void cisco_keepalive_send(hdlc_device *hdlc, u32 type, +static void cisco_keepalive_send(struct net_device *dev, u32 type, u32 par1, u32 par2) { struct sk_buff *skb; @@ -67,12 +67,11 @@ if (!skb) { printk(KERN_WARNING "%s: Memory squeeze on cisco_keepalive_send()\n", - hdlc_to_name(hdlc)); + dev->name); return; } skb_reserve(skb, 4); - cisco_hard_header(skb, hdlc_to_dev(hdlc), CISCO_KEEPALIVE, - NULL, NULL, 0); + cisco_hard_header(skb, dev, CISCO_KEEPALIVE, NULL, NULL, 0); data = (cisco_packet*)skb->tail; data->type = htonl(type); @@ -84,7 +83,7 @@ skb_put(skb, sizeof(cisco_packet)); skb->priority = TC_PRIO_CONTROL; - skb->dev = hdlc_to_dev(hdlc); + skb->dev = dev; skb->nh.raw = skb->data; dev_queue_xmit(skb); @@ -118,7 +117,8 @@ static int cisco_rx(struct sk_buff *skb) { - hdlc_device *hdlc = dev_to_hdlc(skb->dev); + struct net_device *dev = skb->dev; + hdlc_device *hdlc = dev_to_hdlc(dev); hdlc_header *data = (hdlc_header*)skb->data; cisco_packet *cisco_data; struct in_device *in_dev; @@ -142,7 +142,7 @@ skb->len != sizeof(hdlc_header) + CISCO_BIG_PACKET_LEN) { printk(KERN_INFO "%s: Invalid length of Cisco " "control packet (%d bytes)\n", - hdlc_to_name(hdlc), skb->len); + dev->name, skb->len); goto rx_error; } @@ -150,7 +150,7 @@ switch(ntohl (cisco_data->type)) { case CISCO_ADDR_REQ: /* Stolen from syncppp.c :-) */ - in_dev = hdlc_to_dev(hdlc)->ip_ptr; + in_dev = dev->ip_ptr; addr = 0; mask = ~0; /* is the mask correct? */ @@ -158,7 +158,7 @@ struct in_ifaddr **ifap = &in_dev->ifa_list; while (*ifap != NULL) { - if (strcmp(hdlc_to_name(hdlc), + if (strcmp(dev->name, (*ifap)->ifa_label) == 0) { addr = (*ifap)->ifa_local; mask = (*ifap)->ifa_mask; @@ -167,7 +167,7 @@ ifap = &(*ifap)->ifa_next; } - cisco_keepalive_send(hdlc, CISCO_ADDR_REPLY, + cisco_keepalive_send(dev, CISCO_ADDR_REPLY, addr, mask); } dev_kfree_skb_any(skb); @@ -175,7 +175,7 @@ case CISCO_ADDR_REPLY: printk(KERN_INFO "%s: Unexpected Cisco IP address " - "reply\n", hdlc_to_name(hdlc)); + "reply\n", dev->name); goto rx_error; case CISCO_KEEPALIVE_REQ: @@ -190,7 +190,7 @@ days = hrs / 24; hrs -= days * 24; printk(KERN_INFO "%s: Link up (peer " "uptime %ud%uh%um%us)\n", - hdlc_to_name(hdlc), days, hrs, + dev->name, days, hrs, min, sec); } hdlc->state.cisco.up = 1; @@ -201,7 +201,7 @@ } /* switch(keepalive type) */ } /* switch(protocol) */ - printk(KERN_INFO "%s: Unsupported protocol %x\n", hdlc_to_name(hdlc), + printk(KERN_INFO "%s: Unsupported protocol %x\n", dev->name, data->protocol); dev_kfree_skb_any(skb); return NET_RX_DROP; @@ -216,17 +216,18 @@ static void cisco_timer(unsigned long arg) { - hdlc_device *hdlc = (hdlc_device*)arg; + struct net_device *dev = (struct net_device *)arg; + hdlc_device *hdlc = dev_to_hdlc(dev); if (hdlc->state.cisco.up && jiffies - hdlc->state.cisco.last_poll >= hdlc->state.cisco.settings.timeout * HZ) { hdlc->state.cisco.up = 0; - printk(KERN_INFO "%s: Link down\n", hdlc_to_name(hdlc)); - if (netif_carrier_ok(&hdlc->netdev)) - netif_carrier_off(&hdlc->netdev); + printk(KERN_INFO "%s: Link down\n", dev->name); + if (netif_carrier_ok(dev)) + netif_carrier_off(dev); } - cisco_keepalive_send(hdlc, CISCO_KEEPALIVE_REQ, + cisco_keepalive_send(dev, CISCO_KEEPALIVE_REQ, ++hdlc->state.cisco.txseq, hdlc->state.cisco.rxseq); hdlc->state.cisco.timer.expires = jiffies + @@ -238,8 +239,9 @@ -static void cisco_start(hdlc_device *hdlc) +static void cisco_start(struct net_device *dev) { + hdlc_device *hdlc = dev_to_hdlc(dev); hdlc->state.cisco.last_poll = 0; hdlc->state.cisco.up = 0; hdlc->state.cisco.txseq = hdlc->state.cisco.rxseq = 0; @@ -247,27 +249,27 @@ init_timer(&hdlc->state.cisco.timer); hdlc->state.cisco.timer.expires = jiffies + HZ; /*First poll after 1s*/ hdlc->state.cisco.timer.function = cisco_timer; - hdlc->state.cisco.timer.data = (unsigned long)hdlc; + hdlc->state.cisco.timer.data = (unsigned long)dev; add_timer(&hdlc->state.cisco.timer); } -static void cisco_stop(hdlc_device *hdlc) +static void cisco_stop(struct net_device *dev) { - del_timer_sync(&hdlc->state.cisco.timer); - if (netif_carrier_ok(&hdlc->netdev)) - netif_carrier_off(&hdlc->netdev); + del_timer_sync(&dev_to_hdlc(dev)->state.cisco.timer); + if (netif_carrier_ok(dev)) + netif_carrier_off(dev); } -int hdlc_cisco_ioctl(hdlc_device *hdlc, struct ifreq *ifr) +int hdlc_cisco_ioctl(struct net_device *dev, struct ifreq *ifr) { cisco_proto *cisco_s = ifr->ifr_settings.ifs_ifsu.cisco; const size_t size = sizeof(cisco_proto); cisco_proto new_settings; - struct net_device *dev = hdlc_to_dev(hdlc); + hdlc_device *hdlc = dev_to_hdlc(dev); int result; switch (ifr->ifr_settings.type) { @@ -295,7 +297,7 @@ new_settings.timeout < 2) return -EINVAL; - result=hdlc->attach(hdlc, ENCODING_NRZ,PARITY_CRC16_PR1_CCITT); + result=hdlc->attach(dev, ENCODING_NRZ,PARITY_CRC16_PR1_CCITT); if (result) return result; diff -Nru a/drivers/net/wan/hdlc_fr.c b/drivers/net/wan/hdlc_fr.c --- a/drivers/net/wan/hdlc_fr.c Thu Jan 22 18:59:26 2004 +++ b/drivers/net/wan/hdlc_fr.c Thu Jan 22 18:59:26 2004 @@ -146,8 +146,9 @@ } -static inline pvc_device* add_pvc(hdlc_device *hdlc, u16 dlci) +static inline pvc_device* add_pvc(struct net_device *dev, u16 dlci) { + hdlc_device *hdlc = dev_to_hdlc(dev); pvc_device *pvc, **pvc_p = &hdlc->state.fr.first_pvc; while (*pvc_p) { @@ -164,7 +165,7 @@ memset(pvc, 0, sizeof(pvc_device)); pvc->dlci = dlci; - pvc->master = hdlc; + pvc->master = dev; pvc->next = *pvc_p; /* Put it in the chain */ *pvc_p = pvc; return pvc; @@ -311,15 +312,16 @@ { pvc_device *pvc = dev_to_pvc(dev); - if ((hdlc_to_dev(pvc->master)->flags & IFF_UP) == 0) + if ((pvc->master->flags & IFF_UP) == 0) return -EIO; /* Master must be UP in order to activate PVC */ if (pvc->open_count++ == 0) { - if (pvc->master->state.fr.settings.lmi == LMI_NONE) - pvc->state.active = pvc->master->carrier; + hdlc_device *hdlc = dev_to_hdlc(pvc->master); + if (hdlc->state.fr.settings.lmi == LMI_NONE) + pvc->state.active = hdlc->carrier; pvc_carrier(pvc->state.active, pvc); - pvc->master->state.fr.dce_changed = 1; + hdlc->state.fr.dce_changed = 1; } return 0; } @@ -331,11 +333,12 @@ pvc_device *pvc = dev_to_pvc(dev); if (--pvc->open_count == 0) { - if (pvc->master->state.fr.settings.lmi == LMI_NONE) + hdlc_device *hdlc = dev_to_hdlc(pvc->master); + if (hdlc->state.fr.settings.lmi == LMI_NONE) pvc->state.active = 0; - if (pvc->master->state.fr.settings.dce) { - pvc->master->state.fr.dce_changed = 1; + if (hdlc->state.fr.settings.dce) { + hdlc->state.fr.dce_changed = 1; pvc->state.active = 0; } } @@ -362,7 +365,7 @@ } info.dlci = pvc->dlci; - memcpy(info.master, hdlc_to_name(pvc->master), IFNAMSIZ); + memcpy(info.master, pvc->master->name, IFNAMSIZ); if (copy_to_user(ifr->ifr_settings.ifs_ifsu.fr_pvc_info, &info, sizeof(info))) return -EFAULT; @@ -375,8 +378,7 @@ static inline struct net_device_stats *pvc_get_stats(struct net_device *dev) { - return (struct net_device_stats *) - ((char *)dev + sizeof(struct net_device)); + return netdev_priv(dev); } @@ -408,7 +410,7 @@ stats->tx_packets++; if (pvc->state.fecn) /* TX Congestion counter */ stats->tx_compressed++; - skb->dev = hdlc_to_dev(pvc->master); + skb->dev = pvc->master; dev_queue_xmit(skb); return 0; } @@ -434,7 +436,7 @@ static inline void fr_log_dlci_active(pvc_device *pvc) { printk(KERN_INFO "%s: DLCI %d [%s%s%s]%s %s\n", - hdlc_to_name(pvc->master), + pvc->master->name, pvc->dlci, pvc->main ? pvc->main->name : "", pvc->main && pvc->ether ? " " : "", @@ -454,8 +456,9 @@ -static void fr_lmi_send(hdlc_device *hdlc, int fullrep) +static void fr_lmi_send(struct net_device *dev, int fullrep) { + hdlc_device *hdlc = dev_to_hdlc(dev); struct sk_buff *skb; pvc_device *pvc = hdlc->state.fr.first_pvc; int len = (hdlc->state.fr.settings.lmi == LMI_ANSI) ? LMI_ANSI_LENGTH @@ -468,7 +471,7 @@ len += hdlc->state.fr.dce_pvc_count * (2 + stat_len); if (len > HDLC_MAX_MRU) { printk(KERN_WARNING "%s: Too many PVCs while sending " - "LMI full report\n", hdlc_to_name(hdlc)); + "LMI full report\n", dev->name); return; } } @@ -476,7 +479,7 @@ skb = dev_alloc_skb(len); if (!skb) { printk(KERN_WARNING "%s: Memory squeeze on fr_lmi_send()\n", - hdlc_to_name(hdlc)); + dev->name); return; } memset(skb->data, 0, len); @@ -529,7 +532,7 @@ skb_put(skb, i); skb->priority = TC_PRIO_CONTROL; - skb->dev = hdlc_to_dev(hdlc); + skb->dev = dev; skb->nh.raw = skb->data; dev_queue_xmit(skb); @@ -537,14 +540,15 @@ -static void fr_set_link_state(int reliable, hdlc_device *hdlc) +static void fr_set_link_state(int reliable, struct net_device *dev) { + hdlc_device *hdlc = dev_to_hdlc(dev); pvc_device *pvc = hdlc->state.fr.first_pvc; hdlc->state.fr.reliable = reliable; if (reliable) { - if (!netif_carrier_ok(&hdlc->netdev)) - netif_carrier_on(&hdlc->netdev); + if (!netif_carrier_ok(dev)) + netif_carrier_on(dev); hdlc->state.fr.n391cnt = 0; /* Request full status */ hdlc->state.fr.dce_changed = 1; @@ -558,8 +562,8 @@ } } } else { - if (netif_carrier_ok(&hdlc->netdev)) - netif_carrier_off(&hdlc->netdev); + if (netif_carrier_ok(dev)) + netif_carrier_off(dev); while (pvc) { /* Deactivate all PVCs */ pvc_carrier(0, pvc); @@ -574,7 +578,8 @@ static void fr_timer(unsigned long arg) { - hdlc_device *hdlc = (hdlc_device*)arg; + struct net_device *dev = (struct net_device *)arg; + hdlc_device *hdlc = dev_to_hdlc(dev); int i, cnt = 0, reliable; u32 list; @@ -586,7 +591,7 @@ if (hdlc->state.fr.request) { if (hdlc->state.fr.reliable) printk(KERN_INFO "%s: No LMI status reply " - "received\n", hdlc_to_name(hdlc)); + "received\n", dev->name); hdlc->state.fr.last_errors |= 1; } @@ -598,9 +603,9 @@ } if (hdlc->state.fr.reliable != reliable) { - printk(KERN_INFO "%s: Link %sreliable\n", hdlc_to_name(hdlc), + printk(KERN_INFO "%s: Link %sreliable\n", dev->name, reliable ? "" : "un"); - fr_set_link_state(reliable, hdlc); + fr_set_link_state(reliable, dev); } if (hdlc->state.fr.settings.dce) @@ -610,7 +615,7 @@ if (hdlc->state.fr.n391cnt) hdlc->state.fr.n391cnt--; - fr_lmi_send(hdlc, hdlc->state.fr.n391cnt == 0); + fr_lmi_send(dev, hdlc->state.fr.n391cnt == 0); hdlc->state.fr.request = 1; hdlc->state.fr.timer.expires = jiffies + @@ -624,8 +629,9 @@ -static int fr_lmi_recv(hdlc_device *hdlc, struct sk_buff *skb) +static int fr_lmi_recv(struct net_device *dev, struct sk_buff *skb) { + hdlc_device *hdlc = dev_to_hdlc(dev); int stat_len; pvc_device *pvc; int reptype = -1, error, no_ram; @@ -634,14 +640,14 @@ if (skb->len < ((hdlc->state.fr.settings.lmi == LMI_ANSI) ? LMI_ANSI_LENGTH : LMI_LENGTH)) { - printk(KERN_INFO "%s: Short LMI frame\n", hdlc_to_name(hdlc)); + printk(KERN_INFO "%s: Short LMI frame\n", dev->name); return 1; } if (skb->data[5] != (!hdlc->state.fr.settings.dce ? LMI_STATUS : LMI_STATUS_ENQUIRY)) { printk(KERN_INFO "%s: LMI msgtype=%x, Not LMI status %s\n", - hdlc_to_name(hdlc), skb->data[2], + dev->name, skb->data[2], hdlc->state.fr.settings.dce ? "enquiry" : "reply"); return 1; } @@ -652,7 +658,7 @@ ((hdlc->state.fr.settings.lmi == LMI_CCITT) ? LMI_CCITT_REPTYPE : LMI_REPTYPE)) { printk(KERN_INFO "%s: Not a report type=%x\n", - hdlc_to_name(hdlc), skb->data[i]); + dev->name, skb->data[i]); return 1; } i++; @@ -665,7 +671,7 @@ ((hdlc->state.fr.settings.lmi == LMI_CCITT) ? LMI_CCITT_ALIVE : LMI_ALIVE)) { printk(KERN_INFO "%s: Unsupported status element=%x\n", - hdlc_to_name(hdlc), skb->data[i]); + dev->name, skb->data[i]); return 1; } i++; @@ -680,7 +686,7 @@ if (hdlc->state.fr.settings.dce) { if (reptype != LMI_FULLREP && reptype != LMI_INTEGRITY) { printk(KERN_INFO "%s: Unsupported report type=%x\n", - hdlc_to_name(hdlc), reptype); + dev->name, reptype); return 1; } } @@ -716,7 +722,7 @@ hdlc->state.fr.dce_changed = 0; } - fr_lmi_send(hdlc, reptype == LMI_FULLREP ? 1 : 0); + fr_lmi_send(dev, reptype == LMI_FULLREP ? 1 : 0); return 0; } @@ -741,26 +747,26 @@ if (skb->data[i] != ((hdlc->state.fr.settings.lmi == LMI_CCITT) ? LMI_CCITT_PVCSTAT : LMI_PVCSTAT)) { printk(KERN_WARNING "%s: Invalid PVCSTAT ID: %x\n", - hdlc_to_name(hdlc), skb->data[i]); + dev->name, skb->data[i]); return 1; } i++; if (skb->data[i] != stat_len) { printk(KERN_WARNING "%s: Invalid PVCSTAT length: %x\n", - hdlc_to_name(hdlc), skb->data[i]); + dev->name, skb->data[i]); return 1; } i++; dlci = status_to_dlci(skb->data + i, &active, &new); - pvc = add_pvc(hdlc, dlci); + pvc = add_pvc(dev, dlci); if (!pvc && !no_ram) { printk(KERN_WARNING "%s: Memory squeeze on fr_lmi_recv()\n", - hdlc_to_name(hdlc)); + dev->name); no_ram = 1; } @@ -802,7 +808,8 @@ static int fr_rx(struct sk_buff *skb) { - hdlc_device *hdlc = dev_to_hdlc(skb->dev); + struct net_device *ndev = skb->dev; + hdlc_device *hdlc = dev_to_hdlc(ndev); fr_hdr *fh = (fr_hdr*)skb->data; u8 *data = skb->data; u16 dlci; @@ -819,7 +826,7 @@ goto rx_error; /* LMI packet with no LMI? */ if (data[3] == LMI_PROTO) { - if (fr_lmi_recv(hdlc, skb)) + if (fr_lmi_recv(ndev, skb)) goto rx_error; else { /* No request pending */ @@ -831,7 +838,7 @@ } printk(KERN_INFO "%s: Received non-LMI frame with LMI DLCI\n", - hdlc_to_name(hdlc)); + ndev->name); goto rx_error; } @@ -839,7 +846,7 @@ if (!pvc) { #ifdef DEBUG_PKT printk(KERN_INFO "%s: No PVC for received frame's DLCI %d\n", - hdlc_to_name(hdlc), dlci); + ndev->name, dlci); #endif dev_kfree_skb_any(skb); return NET_RX_DROP; @@ -847,7 +854,7 @@ if (pvc->state.fecn != fh->fecn) { #ifdef DEBUG_ECN - printk(KERN_DEBUG "%s: DLCI %d FECN O%s\n", hdlc_to_name(pvc), + printk(KERN_DEBUG "%s: DLCI %d FECN O%s\n", ndev->name, dlci, fh->fecn ? "N" : "FF"); #endif pvc->state.fecn ^= 1; @@ -855,7 +862,7 @@ if (pvc->state.becn != fh->becn) { #ifdef DEBUG_ECN - printk(KERN_DEBUG "%s: DLCI %d BECN O%s\n", hdlc_to_name(pvc), + printk(KERN_DEBUG "%s: DLCI %d BECN O%s\n", ndev->name, dlci, fh->becn ? "N" : "FF"); #endif pvc->state.becn ^= 1; @@ -899,13 +906,13 @@ default: printk(KERN_INFO "%s: Unsupported protocol, OUI=%x " - "PID=%x\n", hdlc_to_name(hdlc), oui, pid); + "PID=%x\n", ndev->name, oui, pid); dev_kfree_skb_any(skb); return NET_RX_DROP; } } else { printk(KERN_INFO "%s: Unsupported protocol, NLPID=%x " - "length = %i\n", hdlc_to_name(hdlc), data[3], skb->len); + "length = %i\n", ndev->name, data[3], skb->len); dev_kfree_skb_any(skb); return NET_RX_DROP; } @@ -932,14 +939,15 @@ -static void fr_start(hdlc_device *hdlc) +static void fr_start(struct net_device *dev) { + hdlc_device *hdlc = dev_to_hdlc(dev); #ifdef DEBUG_LINK printk(KERN_DEBUG "fr_start\n"); #endif if (hdlc->state.fr.settings.lmi != LMI_NONE) { - if (netif_carrier_ok(&hdlc->netdev)) - netif_carrier_off(&hdlc->netdev); + if (netif_carrier_ok(dev)) + netif_carrier_off(dev); hdlc->state.fr.last_poll = 0; hdlc->state.fr.reliable = 0; hdlc->state.fr.dce_changed = 1; @@ -953,28 +961,30 @@ /* First poll after 1 s */ hdlc->state.fr.timer.expires = jiffies + HZ; hdlc->state.fr.timer.function = fr_timer; - hdlc->state.fr.timer.data = (unsigned long)hdlc; + hdlc->state.fr.timer.data = (unsigned long)dev; add_timer(&hdlc->state.fr.timer); } else - fr_set_link_state(1, hdlc); + fr_set_link_state(1, dev); } -static void fr_stop(hdlc_device *hdlc) +static void fr_stop(struct net_device *dev) { + hdlc_device *hdlc = dev_to_hdlc(dev); #ifdef DEBUG_LINK printk(KERN_DEBUG "fr_stop\n"); #endif if (hdlc->state.fr.settings.lmi != LMI_NONE) del_timer_sync(&hdlc->state.fr.timer); - fr_set_link_state(0, hdlc); + fr_set_link_state(0, dev); } -static void fr_close(hdlc_device *hdlc) +static void fr_close(struct net_device *dev) { + hdlc_device *hdlc = dev_to_hdlc(dev); pvc_device *pvc = hdlc->state.fr.first_pvc; while (pvc) { /* Shutdown all PVCs for this FRAD */ @@ -986,10 +996,17 @@ } } +static void dlci_setup(struct net_device *dev) +{ + dev->type = ARPHRD_DLCI; + dev->flags = IFF_POINTOPOINT; + dev->hard_header_len = 10; + dev->addr_len = 2; +} - -static int fr_add_pvc(hdlc_device *hdlc, unsigned int dlci, int type) +static int fr_add_pvc(struct net_device *master, unsigned int dlci, int type) { + hdlc_device *hdlc = dev_to_hdlc(master); pvc_device *pvc = NULL; struct net_device *dev; int result, used; @@ -998,9 +1015,9 @@ if (type == ARPHRD_ETHER) prefix = "pvceth%d"; - if ((pvc = add_pvc(hdlc, dlci)) == NULL) { + if ((pvc = add_pvc(master, dlci)) == NULL) { printk(KERN_WARNING "%s: Memory squeeze on fr_add_pvc()\n", - hdlc_to_name(hdlc)); + master->name); return -ENOBUFS; } @@ -1009,26 +1026,24 @@ used = pvc_is_used(pvc); - dev = kmalloc(sizeof(struct net_device) + - sizeof(struct net_device_stats), GFP_KERNEL); + if (type == ARPHRD_ETHER) + dev = alloc_netdev(sizeof(struct net_device_stats), + "pvceth%d", ether_setup); + else + dev = alloc_netdev(sizeof(struct net_device_stats), + "pvc%d", dlci_setup); + if (!dev) { printk(KERN_WARNING "%s: Memory squeeze on fr_pvc()\n", - hdlc_to_name(hdlc)); + master->name); delete_unused_pvcs(hdlc); return -ENOBUFS; } - memset(dev, 0, sizeof(struct net_device) + - sizeof(struct net_device_stats)); if (type == ARPHRD_ETHER) { - ether_setup(dev); memcpy(dev->dev_addr, "\x00\x01", 2); get_random_bytes(dev->dev_addr + 2, ETH_ALEN - 2); } else { - dev->type = ARPHRD_DLCI; - dev->flags = IFF_POINTOPOINT; - dev->hard_header_len = 10; - dev->addr_len = 2; *(u16*)dev->dev_addr = htons(dlci); dlci_to_q922(dev->broadcast, dlci); } @@ -1042,15 +1057,15 @@ dev->tx_queue_len = 0; dev->priv = pvc; - result = dev_alloc_name(dev, prefix); + result = dev_alloc_name(dev, dev->name); if (result < 0) { - kfree(dev); + free_netdev(dev); delete_unused_pvcs(hdlc); return result; } if (register_netdevice(dev) != 0) { - kfree(dev); + free_netdev(dev); delete_unused_pvcs(hdlc); return -EIO; } @@ -1080,7 +1095,7 @@ if (dev->flags & IFF_UP) return -EBUSY; /* PVC in use */ - unregister_netdevice(dev); /* the destructor will kfree(dev) */ + unregister_netdevice(dev); /* the destructor will free_netdev(dev) */ *get_dev_p(pvc, type) = NULL; if (!pvc_is_used(pvc)) { @@ -1104,7 +1119,8 @@ while (pvc) { pvc_device *next = pvc->next; - if (pvc->main) /* the destructor will kfree(main + ether) */ + /* destructors will free_netdev() main and ether */ + if (pvc->main) unregister_netdevice(pvc->main); if (pvc->ether) @@ -1117,12 +1133,12 @@ -int hdlc_fr_ioctl(hdlc_device *hdlc, struct ifreq *ifr) +int hdlc_fr_ioctl(struct net_device *dev, struct ifreq *ifr) { fr_proto *fr_s = ifr->ifr_settings.ifs_ifsu.fr; const size_t size = sizeof(fr_proto); fr_proto new_settings; - struct net_device *dev = hdlc_to_dev(hdlc); + hdlc_device *hdlc = dev_to_hdlc(dev); fr_proto_pvc pvc; int result; @@ -1163,7 +1179,7 @@ new_settings.dce != 1)) return -EINVAL; - result=hdlc->attach(hdlc, ENCODING_NRZ,PARITY_CRC16_PR1_CCITT); + result=hdlc->attach(dev, ENCODING_NRZ,PARITY_CRC16_PR1_CCITT); if (result) return result; @@ -1210,7 +1226,7 @@ if (ifr->ifr_settings.type == IF_PROTO_FR_ADD_PVC || ifr->ifr_settings.type == IF_PROTO_FR_ADD_ETH_PVC) - return fr_add_pvc(hdlc, pvc.dlci, result); + return fr_add_pvc(dev, pvc.dlci, result); else return fr_del_pvc(hdlc, pvc.dlci, result); } diff -Nru a/drivers/net/wan/hdlc_generic.c b/drivers/net/wan/hdlc_generic.c --- a/drivers/net/wan/hdlc_generic.c Thu Jan 22 18:59:23 2004 +++ b/drivers/net/wan/hdlc_generic.c Thu Jan 22 18:59:23 2004 @@ -50,7 +50,7 @@ static struct net_device_stats *hdlc_get_stats(struct net_device *dev) { - return &dev_to_hdlc(dev)->stats; + return hdlc_stats(dev); } @@ -69,8 +69,9 @@ -void hdlc_set_carrier(int on, hdlc_device *hdlc) +void hdlc_set_carrier(int on, struct net_device *dev) { + hdlc_device *hdlc = dev_to_hdlc(dev); on = on ? 1 : 0; #ifdef DEBUG_LINK @@ -82,7 +83,7 @@ if (hdlc->carrier == on) goto carrier_exit; /* no change in DCD line level */ - printk(KERN_INFO "%s: carrier %s\n", hdlc_to_name(hdlc), + printk(KERN_INFO "%s: carrier %s\n", dev->name, on ? "ON" : "off"); hdlc->carrier = on; @@ -91,15 +92,15 @@ if (hdlc->carrier) { if (hdlc->proto.start) - hdlc->proto.start(hdlc); - else if (!netif_carrier_ok(&hdlc->netdev)) - netif_carrier_on(&hdlc->netdev); + hdlc->proto.start(dev); + else if (!netif_carrier_ok(dev)) + netif_carrier_on(dev); } else { /* no carrier */ if (hdlc->proto.stop) - hdlc->proto.stop(hdlc); - else if (netif_carrier_ok(&hdlc->netdev)) - netif_carrier_off(&hdlc->netdev); + hdlc->proto.stop(dev); + else if (netif_carrier_ok(dev)) + netif_carrier_off(dev); } carrier_exit: @@ -108,8 +109,9 @@ /* Must be called by hardware driver when HDLC device is being opened */ -int hdlc_open(hdlc_device *hdlc) +int hdlc_open(struct net_device *dev) { + hdlc_device *hdlc = dev_to_hdlc(dev); #ifdef DEBUG_LINK printk(KERN_DEBUG "hdlc_open carrier %i open %i\n", hdlc->carrier, hdlc->open); @@ -119,7 +121,7 @@ return -ENOSYS; /* no protocol attached */ if (hdlc->proto.open) { - int result = hdlc->proto.open(hdlc); + int result = hdlc->proto.open(dev); if (result) return result; } @@ -128,12 +130,12 @@ if (hdlc->carrier) { if (hdlc->proto.start) - hdlc->proto.start(hdlc); - else if (!netif_carrier_ok(&hdlc->netdev)) - netif_carrier_on(&hdlc->netdev); + hdlc->proto.start(dev); + else if (!netif_carrier_ok(dev)) + netif_carrier_on(dev); - } else if (netif_carrier_ok(&hdlc->netdev)) - netif_carrier_off(&hdlc->netdev); + } else if (netif_carrier_ok(dev)) + netif_carrier_off(dev); hdlc->open = 1; @@ -144,8 +146,9 @@ /* Must be called by hardware driver when HDLC device is being closed */ -void hdlc_close(hdlc_device *hdlc) +void hdlc_close(struct net_device *dev) { + hdlc_device *hdlc = dev_to_hdlc(dev); #ifdef DEBUG_LINK printk(KERN_DEBUG "hdlc_close carrier %i open %i\n", hdlc->carrier, hdlc->open); @@ -155,38 +158,38 @@ hdlc->open = 0; if (hdlc->carrier && hdlc->proto.stop) - hdlc->proto.stop(hdlc); + hdlc->proto.stop(dev); spin_unlock_irq(&hdlc->state_lock); if (hdlc->proto.close) - hdlc->proto.close(hdlc); + hdlc->proto.close(dev); } #ifndef CONFIG_HDLC_RAW -#define hdlc_raw_ioctl(hdlc, ifr) -ENOSYS +#define hdlc_raw_ioctl(dev, ifr) -ENOSYS #endif #ifndef CONFIG_HDLC_RAW_ETH -#define hdlc_raw_eth_ioctl(hdlc, ifr) -ENOSYS +#define hdlc_raw_eth_ioctl(dev, ifr) -ENOSYS #endif #ifndef CONFIG_HDLC_PPP -#define hdlc_ppp_ioctl(hdlc, ifr) -ENOSYS +#define hdlc_ppp_ioctl(dev, ifr) -ENOSYS #endif #ifndef CONFIG_HDLC_CISCO -#define hdlc_cisco_ioctl(hdlc, ifr) -ENOSYS +#define hdlc_cisco_ioctl(dev, ifr) -ENOSYS #endif #ifndef CONFIG_HDLC_FR -#define hdlc_fr_ioctl(hdlc, ifr) -ENOSYS +#define hdlc_fr_ioctl(dev, ifr) -ENOSYS #endif #ifndef CONFIG_HDLC_X25 -#define hdlc_x25_ioctl(hdlc, ifr) -ENOSYS +#define hdlc_x25_ioctl(dev, ifr) -ENOSYS #endif @@ -213,22 +216,49 @@ } switch(proto) { - case IF_PROTO_HDLC: return hdlc_raw_ioctl(hdlc, ifr); - case IF_PROTO_HDLC_ETH: return hdlc_raw_eth_ioctl(hdlc, ifr); - case IF_PROTO_PPP: return hdlc_ppp_ioctl(hdlc, ifr); - case IF_PROTO_CISCO: return hdlc_cisco_ioctl(hdlc, ifr); - case IF_PROTO_FR: return hdlc_fr_ioctl(hdlc, ifr); - case IF_PROTO_X25: return hdlc_x25_ioctl(hdlc, ifr); + case IF_PROTO_HDLC: return hdlc_raw_ioctl(dev, ifr); + case IF_PROTO_HDLC_ETH: return hdlc_raw_eth_ioctl(dev, ifr); + case IF_PROTO_PPP: return hdlc_ppp_ioctl(dev, ifr); + case IF_PROTO_CISCO: return hdlc_cisco_ioctl(dev, ifr); + case IF_PROTO_FR: return hdlc_fr_ioctl(dev, ifr); + case IF_PROTO_X25: return hdlc_x25_ioctl(dev, ifr); default: return -EINVAL; } } +static void hdlc_setup(struct net_device *dev) +{ + hdlc_device *hdlc = dev_to_hdlc(dev); + + dev->get_stats = hdlc_get_stats; + dev->change_mtu = hdlc_change_mtu; + dev->mtu = HDLC_MAX_MTU; + + dev->type = ARPHRD_RAWHDLC; + dev->hard_header_len = 16; + + dev->flags = IFF_POINTOPOINT | IFF_NOARP; + + hdlc->proto.id = -1; + hdlc->proto.detach = NULL; + hdlc->carrier = 1; + hdlc->open = 0; + spin_lock_init(&hdlc->state_lock); +} +struct net_device *alloc_hdlcdev(void *priv) +{ + struct net_device *dev; + dev = alloc_netdev(sizeof(hdlc_device), "hdlc%d", hdlc_setup); + if (dev) + dev_to_hdlc(dev)->priv = priv; + return dev; +} -int register_hdlc_device(hdlc_device *hdlc) +int register_hdlc_device(struct net_device *dev) { int result; - struct net_device *dev = hdlc_to_dev(hdlc); + hdlc_device *hdlc = dev_to_hdlc(dev); dev->get_stats = hdlc_get_stats; dev->change_mtu = hdlc_change_mtu; @@ -258,11 +288,11 @@ -void unregister_hdlc_device(hdlc_device *hdlc) +void unregister_hdlc_device(struct net_device *dev) { rtnl_lock(); - hdlc_proto_detach(hdlc); - unregister_netdevice(hdlc_to_dev(hdlc)); + hdlc_proto_detach(dev_to_hdlc(dev)); + unregister_netdevice(dev); rtnl_unlock(); } @@ -276,6 +306,7 @@ EXPORT_SYMBOL(hdlc_close); EXPORT_SYMBOL(hdlc_set_carrier); EXPORT_SYMBOL(hdlc_ioctl); +EXPORT_SYMBOL(alloc_hdlcdev); EXPORT_SYMBOL(register_hdlc_device); EXPORT_SYMBOL(unregister_hdlc_device); diff -Nru a/drivers/net/wan/hdlc_ppp.c b/drivers/net/wan/hdlc_ppp.c --- a/drivers/net/wan/hdlc_ppp.c Thu Jan 22 18:59:23 2004 +++ b/drivers/net/wan/hdlc_ppp.c Thu Jan 22 18:59:23 2004 @@ -24,9 +24,9 @@ #include -static int ppp_open(hdlc_device *hdlc) +static int ppp_open(struct net_device *dev) { - struct net_device *dev = hdlc_to_dev(hdlc); + hdlc_device *hdlc = dev_to_hdlc(dev); void *old_ioctl; int result; @@ -52,9 +52,9 @@ -static void ppp_close(hdlc_device *hdlc) +static void ppp_close(struct net_device *dev) { - struct net_device *dev = hdlc_to_dev(hdlc); + hdlc_device *hdlc = dev_to_hdlc(dev); sppp_close(dev); sppp_detach(dev); @@ -74,9 +74,9 @@ -int hdlc_ppp_ioctl(hdlc_device *hdlc, struct ifreq *ifr) +int hdlc_ppp_ioctl(struct net_device *dev, struct ifreq *ifr) { - struct net_device *dev = hdlc_to_dev(hdlc); + hdlc_device *hdlc = dev_to_hdlc(dev); int result; switch (ifr->ifr_settings.type) { @@ -93,7 +93,7 @@ /* no settable parameters */ - result=hdlc->attach(hdlc, ENCODING_NRZ,PARITY_CRC16_PR1_CCITT); + result=hdlc->attach(dev, ENCODING_NRZ,PARITY_CRC16_PR1_CCITT); if (result) return result; diff -Nru a/drivers/net/wan/hdlc_raw.c b/drivers/net/wan/hdlc_raw.c --- a/drivers/net/wan/hdlc_raw.c Thu Jan 22 18:59:25 2004 +++ b/drivers/net/wan/hdlc_raw.c Thu Jan 22 18:59:25 2004 @@ -32,12 +32,12 @@ -int hdlc_raw_ioctl(hdlc_device *hdlc, struct ifreq *ifr) +int hdlc_raw_ioctl(struct net_device *dev, struct ifreq *ifr) { raw_hdlc_proto *raw_s = ifr->ifr_settings.ifs_ifsu.raw_hdlc; const size_t size = sizeof(raw_hdlc_proto); raw_hdlc_proto new_settings; - struct net_device *dev = hdlc_to_dev(hdlc); + hdlc_device *hdlc = dev_to_hdlc(dev); int result; switch (ifr->ifr_settings.type) { @@ -67,7 +67,7 @@ if (new_settings.parity == PARITY_DEFAULT) new_settings.parity = PARITY_CRC16_PR1_CCITT; - result = hdlc->attach(hdlc, new_settings.encoding, + result = hdlc->attach(dev, new_settings.encoding, new_settings.parity); if (result) return result; diff -Nru a/drivers/net/wan/hdlc_raw_eth.c b/drivers/net/wan/hdlc_raw_eth.c --- a/drivers/net/wan/hdlc_raw_eth.c Thu Jan 22 18:59:25 2004 +++ b/drivers/net/wan/hdlc_raw_eth.c Thu Jan 22 18:59:25 2004 @@ -33,7 +33,7 @@ int len = skb->len; if (skb_tailroom(skb) < pad) if (pskb_expand_head(skb, 0, pad, GFP_ATOMIC)) { - dev_to_hdlc(dev)->stats.tx_dropped++; + hdlc_stats(dev)->tx_dropped++; dev_kfree_skb(skb); return 0; } @@ -44,12 +44,12 @@ } -int hdlc_raw_eth_ioctl(hdlc_device *hdlc, struct ifreq *ifr) +int hdlc_raw_eth_ioctl(struct net_device *dev, struct ifreq *ifr) { raw_hdlc_proto *raw_s = ifr->ifr_settings.ifs_ifsu.raw_hdlc; const size_t size = sizeof(raw_hdlc_proto); raw_hdlc_proto new_settings; - struct net_device *dev = hdlc_to_dev(hdlc); + hdlc_device *hdlc = dev_to_hdlc(dev); int result; void *old_ch_mtu; int old_qlen; @@ -81,7 +81,7 @@ if (new_settings.parity == PARITY_DEFAULT) new_settings.parity = PARITY_CRC16_PR1_CCITT; - result = hdlc->attach(hdlc, new_settings.encoding, + result = hdlc->attach(dev, new_settings.encoding, new_settings.parity); if (result) return result; diff -Nru a/drivers/net/wan/hdlc_x25.c b/drivers/net/wan/hdlc_x25.c --- a/drivers/net/wan/hdlc_x25.c Thu Jan 22 18:59:27 2004 +++ b/drivers/net/wan/hdlc_x25.c Thu Jan 22 18:59:27 2004 @@ -25,21 +25,20 @@ /* These functions are callbacks called by LAPB layer */ -static void x25_connect_disconnect(void *token, int reason, int code) +static void x25_connect_disconnect(struct net_device *dev, int reason, int code) { - hdlc_device *hdlc = token; struct sk_buff *skb; unsigned char *ptr; if ((skb = dev_alloc_skb(1)) == NULL) { - printk(KERN_ERR "%s: out of memory\n", hdlc_to_name(hdlc)); + printk(KERN_ERR "%s: out of memory\n", dev->name); return; } ptr = skb_put(skb, 1); *ptr = code; - skb->dev = hdlc_to_dev(hdlc); + skb->dev = dev; skb->protocol = htons(ETH_P_X25); skb->mac.raw = skb->data; skb->pkt_type = PACKET_HOST; @@ -49,23 +48,22 @@ -static void x25_connected(void *token, int reason) +static void x25_connected(struct net_device *dev, int reason) { - x25_connect_disconnect(token, reason, 1); + x25_connect_disconnect(dev, reason, 1); } -static void x25_disconnected(void *token, int reason) +static void x25_disconnected(struct net_device *dev, int reason) { - x25_connect_disconnect(token, reason, 2); + x25_connect_disconnect(dev, reason, 2); } -static int x25_data_indication(void *token, struct sk_buff *skb) +static int x25_data_indication(struct net_device *dev, struct sk_buff *skb) { - hdlc_device *hdlc = token; unsigned char *ptr; skb_push(skb, 1); @@ -76,7 +74,7 @@ ptr = skb->data; *ptr = 0; - skb->dev = hdlc_to_dev(hdlc); + skb->dev = dev; skb->protocol = htons(ETH_P_X25); skb->mac.raw = skb->data; skb->pkt_type = PACKET_HOST; @@ -86,17 +84,16 @@ -static void x25_data_transmit(void *token, struct sk_buff *skb) +static void x25_data_transmit(struct net_device *dev, struct sk_buff *skb) { - hdlc_device *hdlc = token; - hdlc->xmit(skb, hdlc_to_dev(hdlc)); /* Ignore return value :-( */ + hdlc_device *hdlc = dev_to_hdlc(dev); + hdlc->xmit(skb, dev); /* Ignore return value :-( */ } static int x25_xmit(struct sk_buff *skb, struct net_device *dev) { - hdlc_device *hdlc = dev_to_hdlc(dev); int result; @@ -104,31 +101,31 @@ switch (skb->data[0]) { case 0: /* Data to be transmitted */ skb_pull(skb, 1); - if ((result = lapb_data_request(hdlc, skb)) != LAPB_OK) + if ((result = lapb_data_request(dev, skb)) != LAPB_OK) dev_kfree_skb(skb); return 0; case 1: - if ((result = lapb_connect_request(hdlc))!= LAPB_OK) { + if ((result = lapb_connect_request(dev))!= LAPB_OK) { if (result == LAPB_CONNECTED) /* Send connect confirm. msg to level 3 */ - x25_connected(hdlc, 0); + x25_connected(dev, 0); else printk(KERN_ERR "%s: LAPB connect request " "failed, error code = %i\n", - hdlc_to_name(hdlc), result); + dev->name, result); } break; case 2: - if ((result = lapb_disconnect_request(hdlc)) != LAPB_OK) { + if ((result = lapb_disconnect_request(dev)) != LAPB_OK) { if (result == LAPB_NOTCONNECTED) /* Send disconnect confirm. msg to level 3 */ - x25_disconnected(hdlc, 0); + x25_disconnected(dev, 0); else printk(KERN_ERR "%s: LAPB disconnect request " "failed, error code = %i\n", - hdlc_to_name(hdlc), result); + dev->name, result); } break; @@ -142,7 +139,7 @@ -static int x25_open(hdlc_device *hdlc) +static int x25_open(struct net_device *dev) { struct lapb_register_struct cb; int result; @@ -154,7 +151,7 @@ cb.data_indication = x25_data_indication; cb.data_transmit = x25_data_transmit; - result = lapb_register(hdlc, &cb); + result = lapb_register(dev, &cb); if (result != LAPB_OK) return result; return 0; @@ -162,9 +159,9 @@ -static void x25_close(hdlc_device *hdlc) +static void x25_close(struct net_device *dev) { - lapb_unregister(hdlc); + lapb_unregister(dev); } @@ -178,7 +175,7 @@ return NET_RX_DROP; } - if (lapb_data_received(hdlc, skb) == LAPB_OK) + if (lapb_data_received(skb->dev, skb) == LAPB_OK) return NET_RX_SUCCESS; hdlc->stats.rx_errors++; @@ -188,9 +185,9 @@ -int hdlc_x25_ioctl(hdlc_device *hdlc, struct ifreq *ifr) +int hdlc_x25_ioctl(struct net_device *dev, struct ifreq *ifr) { - struct net_device *dev = hdlc_to_dev(hdlc); + hdlc_device *hdlc = dev_to_hdlc(dev); int result; switch (ifr->ifr_settings.type) { @@ -205,7 +202,7 @@ if(dev->flags & IFF_UP) return -EBUSY; - result=hdlc->attach(hdlc, ENCODING_NRZ,PARITY_CRC16_PR1_CCITT); + result=hdlc->attach(dev, ENCODING_NRZ,PARITY_CRC16_PR1_CCITT); if (result) return result; diff -Nru a/drivers/net/wan/hostess_sv11.c b/drivers/net/wan/hostess_sv11.c --- a/drivers/net/wan/hostess_sv11.c Thu Jan 22 18:59:26 2004 +++ b/drivers/net/wan/hostess_sv11.c Thu Jan 22 18:59:26 2004 @@ -122,7 +122,6 @@ */ netif_start_queue(d); - MOD_INC_USE_COUNT; return 0; } @@ -154,7 +153,6 @@ z8530_sync_txdma_close(d, &sv11->sync.chanA); break; } - MOD_DEC_USE_COUNT; return 0; } @@ -203,6 +201,16 @@ return 0; } +static void sv11_setup(struct net_device *dev) +{ + dev->open = hostess_open; + dev->stop = hostess_close; + dev->hard_start_xmit = hostess_queue_xmit; + dev->get_stats = hostess_get_stats; + dev->do_ioctl = hostess_ioctl; + dev->neigh_setup = hostess_neigh_setup_dev; +} + /* * Description block for a Comtrol Hostess SV11 card */ @@ -229,10 +237,12 @@ memset(sv, 0, sizeof(*sv)); sv->if_ptr=&sv->netdev; - sv->netdev.dev=(struct net_device *)kmalloc(sizeof(struct net_device), GFP_KERNEL); + sv->netdev.dev = alloc_netdev(0, "hdlc%d", sv11_setup); if(!sv->netdev.dev) goto fail2; + SET_MODULE_OWNER(sv->netdev.dev); + dev=&sv->sync; /* @@ -326,23 +336,14 @@ d->base_addr = iobase; d->irq = irq; d->priv = sv; - d->init = NULL; - - d->open = hostess_open; - d->stop = hostess_close; - d->hard_start_xmit = hostess_queue_xmit; - d->get_stats = hostess_get_stats; - d->set_multicast_list = NULL; - d->do_ioctl = hostess_ioctl; - d->neigh_setup = hostess_neigh_setup_dev; - d->set_mac_address = NULL; if(register_netdev(d)) { printk(KERN_ERR "%s: unable to register device.\n", d->name); - goto fail; - } + sppp_detach(d); + goto dmafail2; + } z8530_describe(dev, "I/O", iobase); dev->active=1; @@ -357,7 +358,7 @@ fail: free_irq(irq, dev); fail1: - kfree(sv->netdev.dev); + free_netdev(sv->netdev.dev); fail2: kfree(sv); fail3: @@ -368,8 +369,8 @@ static void sv11_shutdown(struct sv11_device *dev) { sppp_detach(dev->netdev.dev); - z8530_shutdown(&dev->sync); unregister_netdev(dev->netdev.dev); + z8530_shutdown(&dev->sync); free_irq(dev->sync.irq, dev); if(dma) { @@ -378,6 +379,8 @@ free_dma(dev->sync.chanA.txdma); } release_region(dev->sync.chanA.ctrlio-1, 8); + free_netdev(dev->netdev.dev); + kfree(dev); } #ifdef MODULE diff -Nru a/drivers/net/wan/lapbether.c b/drivers/net/wan/lapbether.c --- a/drivers/net/wan/lapbether.c Thu Jan 22 18:59:24 2004 +++ b/drivers/net/wan/lapbether.c Thu Jan 22 18:59:24 2004 @@ -110,7 +110,7 @@ skb_pull(skb, 2); /* Remove the length bytes */ skb_trim(skb, len); /* Set the length of the data */ - if ((err = lapb_data_received(lapbeth, skb)) != LAPB_OK) { + if ((err = lapb_data_received(lapbeth->axdev, skb)) != LAPB_OK) { printk(KERN_DEBUG "lapbether: lapb_data_received err - %d\n", err); goto drop_unlock; } @@ -125,9 +125,8 @@ return 0; } -static int lapbeth_data_indication(void *token, struct sk_buff *skb) +static int lapbeth_data_indication(struct net_device *dev, struct sk_buff *skb) { - struct lapbethdev *lapbeth = (struct lapbethdev *)token; unsigned char *ptr; skb_push(skb, 1); @@ -138,7 +137,7 @@ ptr = skb->data; *ptr = 0x00; - skb->dev = lapbeth->axdev; + skb->dev = dev; skb->protocol = htons(ETH_P_X25); skb->mac.raw = skb->data; skb->pkt_type = PACKET_HOST; @@ -152,7 +151,6 @@ */ static int lapbeth_xmit(struct sk_buff *skb, struct net_device *dev) { - struct lapbethdev *lapbeth = (struct lapbethdev *)dev->priv; int err = -ENODEV; /* @@ -168,12 +166,12 @@ err = 0; break; case 0x01: - if ((err = lapb_connect_request(lapbeth)) != LAPB_OK) + if ((err = lapb_connect_request(dev)) != LAPB_OK) printk(KERN_ERR "lapbeth: lapb_connect_request " "error: %d\n", err); goto drop_ok; case 0x02: - if ((err = lapb_disconnect_request(lapbeth)) != LAPB_OK) + if ((err = lapb_disconnect_request(dev)) != LAPB_OK) printk(KERN_ERR "lapbeth: lapb_disconnect_request " "err: %d\n", err); /* Fall thru */ @@ -183,7 +181,7 @@ skb_pull(skb, 1); - if ((err = lapb_data_request(lapbeth, skb)) != LAPB_OK) { + if ((err = lapb_data_request(dev, skb)) != LAPB_OK) { printk(KERN_ERR "lapbeth: lapb_data_request error - %d\n", err); err = -ENOMEM; goto drop; @@ -198,9 +196,9 @@ goto out; } -static void lapbeth_data_transmit(void *token, struct sk_buff *skb) +static void lapbeth_data_transmit(struct net_device *ndev, struct sk_buff *skb) { - struct lapbethdev *lapbeth = (struct lapbethdev *)token; + struct lapbethdev *lapbeth = ndev->priv; unsigned char *ptr; struct net_device *dev; int size = skb->len; @@ -222,9 +220,8 @@ dev_queue_xmit(skb); } -static void lapbeth_connected(void *token, int reason) +static void lapbeth_connected(struct net_device *dev, int reason) { - struct lapbethdev *lapbeth = (struct lapbethdev *)token; unsigned char *ptr; struct sk_buff *skb = dev_alloc_skb(1); @@ -236,7 +233,7 @@ ptr = skb_put(skb, 1); *ptr = 0x01; - skb->dev = lapbeth->axdev; + skb->dev = dev; skb->protocol = htons(ETH_P_X25); skb->mac.raw = skb->data; skb->pkt_type = PACKET_HOST; @@ -245,9 +242,8 @@ netif_rx(skb); } -static void lapbeth_disconnected(void *token, int reason) +static void lapbeth_disconnected(struct net_device *dev, int reason) { - struct lapbethdev *lapbeth = (struct lapbethdev *)token; unsigned char *ptr; struct sk_buff *skb = dev_alloc_skb(1); @@ -259,7 +255,7 @@ ptr = skb_put(skb, 1); *ptr = 0x02; - skb->dev = lapbeth->axdev; + skb->dev = dev; skb->protocol = htons(ETH_P_X25); skb->mac.raw = skb->data; skb->pkt_type = PACKET_HOST; @@ -303,11 +299,9 @@ */ static int lapbeth_open(struct net_device *dev) { - struct lapbethdev *lapbeth; int err; - lapbeth = (struct lapbethdev *)dev->priv; - if ((err = lapb_register(lapbeth, &lapbeth_callbacks)) != LAPB_OK) { + if ((err = lapb_register(dev, &lapbeth_callbacks)) != LAPB_OK) { printk(KERN_ERR "lapbeth: lapb_register error - %d\n", err); return -ENODEV; } @@ -318,12 +312,11 @@ static int lapbeth_close(struct net_device *dev) { - struct lapbethdev *lapbeth = (struct lapbethdev *)dev->priv; int err; netif_stop_queue(dev); - if ((err = lapb_unregister(lapbeth)) != LAPB_OK) + if ((err = lapb_unregister(dev)) != LAPB_OK) printk(KERN_ERR "lapbeth: lapb_unregister error - %d\n", err); return 0; @@ -382,6 +375,7 @@ return rc; fail: dev_put(dev); + free_netdev(ndev); kfree(lapbeth); goto out; } diff -Nru a/drivers/net/wan/lmc/lmc_main.c b/drivers/net/wan/lmc/lmc_main.c --- a/drivers/net/wan/lmc/lmc_main.c Thu Jan 22 18:59:24 2004 +++ b/drivers/net/wan/lmc/lmc_main.c Thu Jan 22 18:59:24 2004 @@ -78,30 +78,22 @@ #include "lmc_debug.h" #include "lmc_proto.h" - -static int Lmc_Count = 0; -static struct net_device *Lmc_root_dev = NULL; -static u8 cards_found = 0; - static int lmc_first_load = 0; -int LMC_PKT_BUF_SZ = 1542; +static int LMC_PKT_BUF_SZ = 1542; -#ifdef MODULE static struct pci_device_id lmc_pci_tbl[] = { - { 0x1011, 0x009, 0x1379, PCI_ANY_ID, 0, 0, 0}, - { 0, } + { PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_TULIP_FAST, + PCI_VENDOR_ID_LMC, PCI_ANY_ID }, + { PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_TULIP_FAST, + PCI_ANY_ID, PCI_VENDOR_ID_LMC }, + { 0 } }; MODULE_DEVICE_TABLE(pci, lmc_pci_tbl); - MODULE_LICENSE("GPL"); -#endif -int lmc_probe_fake(struct net_device *dev); -static struct net_device *lmc_probe1(struct net_device *dev, unsigned long ioaddr, unsigned int irq, - int chip_id, int subdevice, int board_idx); static int lmc_start_xmit(struct sk_buff *skb, struct net_device *dev); static int lmc_start_xmit(struct sk_buff *skb, struct net_device *dev); static int lmc_rx (struct net_device *dev); @@ -115,12 +107,9 @@ static void lmc_running_reset(struct net_device *dev); static int lmc_ifdown(struct net_device * const); static void lmc_watchdog(unsigned long data); -static int lmc_init(struct net_device * const); static void lmc_reset(lmc_softc_t * const sc); static void lmc_dec_reset(lmc_softc_t * const sc); static void lmc_driver_timeout(struct net_device *dev); -int lmc_setup(void); - /* * linux reserves 16 device specific IOCTLs. We call them @@ -815,67 +804,77 @@ } -static int lmc_init(struct net_device * const dev) /*fold00*/ +static void lmc_setup(struct net_device * const dev) /*fold00*/ { - lmc_trace(dev, "lmc_init in"); - lmc_trace(dev, "lmc_init out"); - - return 0; + lmc_trace(dev, "lmc_setup in"); + + dev->type = ARPHRD_HDLC; + dev->hard_start_xmit = lmc_start_xmit; + dev->open = lmc_open; + dev->stop = lmc_close; + dev->get_stats = lmc_get_stats; + dev->do_ioctl = lmc_ioctl; + dev->set_config = lmc_set_config; + dev->tx_timeout = lmc_driver_timeout; + dev->watchdog_timeo = (HZ); /* 1 second */ + + lmc_trace(dev, "lmc_setup out"); } -/* This initializes each card from lmc_probe() */ -static struct net_device *lmc_probe1 (struct net_device *dev, unsigned long ioaddr, unsigned int irq, /*fold00*/ - int chip_id, int subdevice, int board_idx) + +static int __devinit lmc_init_one(struct pci_dev *pdev, + const struct pci_device_id *ent) { - lmc_softc_t *sc = NULL; + struct net_device *dev; + lmc_softc_t *sc; + u16 subdevice; u_int16_t AdapModelNum; - - /* - * Allocate our own device structure - */ - - dev = kmalloc (sizeof (struct net_device)+8, GFP_KERNEL); - if (dev == NULL){ - printk (KERN_ERR "lmc: kmalloc for device failed\n"); - return NULL; - } - memset (dev, 0, sizeof (struct net_device)); - + int err = -ENOMEM; + static int cards_found; #ifndef GCOM - /* - * Switch to common hdlc%d naming. We name by type not by vendor - */ - - dev_alloc_name(dev, "hdlc%d"); + /* We name by type not by vendor */ + static const char lmcname[] = "hdlc%d"; #else - /* + /* * GCOM uses LMC vendor name so that clients can know which card * to attach to. */ - dev_alloc_name(dev, "lmc%d"); + static const char lmcname[] = "lmc%d"; #endif - lmc_trace(dev, "lmc_probe1 in"); + + /* + * Allocate our own device structure + */ + dev = alloc_netdev(sizeof(lmc_softc_t), lmcname, lmc_setup); + if (!dev) { + printk (KERN_ERR "lmc:alloc_netdev for device failed\n"); + goto out1; + } + + lmc_trace(dev, "lmc_init_one in"); + + err = pci_enable_device(pdev); + if (err) { + printk(KERN_ERR "lmc: pci enable failed:%d\n", err); + goto out2; + } - Lmc_Count++; + if (pci_request_regions(pdev, "lmc")) { + printk(KERN_ERR "lmc: pci_request_region failed\n"); + err = -EIO; + goto out3; + } + + pci_set_drvdata(pdev, dev); if(lmc_first_load == 0){ - printk(KERN_INFO "Lan Media Corporation WAN Driver Version %d.%d.%d\n",DRIVER_MAJOR_VERSION, DRIVER_MINOR_VERSION,DRIVER_SUB_VERSION); + printk(KERN_INFO "Lan Media Corporation WAN Driver Version %d.%d.%d\n", + DRIVER_MAJOR_VERSION, DRIVER_MINOR_VERSION,DRIVER_SUB_VERSION); lmc_first_load = 1; } - /* - * Allocate space for the private data structure - */ - - sc = kmalloc (sizeof (lmc_softc_t), GFP_KERNEL); - if (sc == NULL) { - printk (KERN_WARNING "%s: Cannot allocate memory for device state\n", - dev->name); - return (NULL); - } - memset (sc, 0, sizeof (lmc_softc_t)); - dev->priv = sc; + sc = dev->priv; sc->lmc_device = dev; sc->name = dev->name; @@ -883,8 +882,12 @@ /* An ioctl can cause a subsequent detach for raw frame interface */ sc->if_type = LMC_PPP; sc->check = 0xBEAFCAFE; - dev->base_addr = ioaddr; - dev->irq = irq; + dev->base_addr = pci_resource_start(pdev, 0); + dev->irq = pdev->irq; + + SET_MODULE_OWNER(dev); + SET_NETDEV_DEV(dev, &pdev->dev); + /* * This will get the protocol layer ready and do any 1 time init's * Must have a valid sc and dev structure @@ -893,19 +896,6 @@ lmc_proto_attach(sc); - /* Just fill in the entries for the device */ - - dev->init = lmc_init; - dev->type = ARPHRD_HDLC; - dev->hard_start_xmit = lmc_start_xmit; - dev->open = lmc_open; - dev->stop = lmc_close; - dev->get_stats = lmc_get_stats; - dev->do_ioctl = lmc_ioctl; - dev->set_config = lmc_set_config; - dev->tx_timeout = lmc_driver_timeout; - dev->watchdog_timeo = (HZ); /* 1 second */ - /* * Why were we changing this??? dev->tx_queue_len = 100; @@ -914,44 +904,45 @@ /* Init the spin lock so can call it latter */ spin_lock_init(&sc->lmc_lock); + pci_set_master(pdev); - printk ("%s: detected at %lx, irq %d\n", dev->name, ioaddr, dev->irq); + printk ("%s: detected at %lx, irq %d\n", dev->name, + dev->base_addr, dev->irq); if (register_netdev (dev) != 0) { printk (KERN_ERR "%s: register_netdev failed.\n", dev->name); - lmc_proto_detach(sc); - kfree (dev->priv); - kfree (dev); - return NULL; + goto out4; } - /* - * Request the region of registers we need, so that - * later on, no one else will take our card away from - * us. - */ - request_region (ioaddr, LMC_REG_RANGE, dev->name); - sc->lmc_cardtype = LMC_CARDTYPE_UNKNOWN; sc->lmc_timing = LMC_CTL_CLOCK_SOURCE_EXT; + /* + * + * Check either the subvendor or the subdevice, some systems reverse + * the setting in the bois, seems to be version and arch dependent? + * Fix the error, exchange the two values + */ + if ((subdevice = pdev->subsystem_device) == PCI_VENDOR_ID_LMC) + subdevice = pdev->subsystem_vendor; + switch (subdevice) { - case PCI_PRODUCT_LMC_HSSI: + case PCI_DEVICE_ID_LMC_HSSI: printk ("%s: LMC HSSI\n", dev->name); sc->lmc_cardtype = LMC_CARDTYPE_HSSI; sc->lmc_media = &lmc_hssi_media; break; - case PCI_PRODUCT_LMC_DS3: + case PCI_DEVICE_ID_LMC_DS3: printk ("%s: LMC DS3\n", dev->name); sc->lmc_cardtype = LMC_CARDTYPE_DS3; sc->lmc_media = &lmc_ds3_media; break; - case PCI_PRODUCT_LMC_SSI: + case PCI_DEVICE_ID_LMC_SSI: printk ("%s: LMC SSI\n", dev->name); sc->lmc_cardtype = LMC_CARDTYPE_SSI; sc->lmc_media = &lmc_ssi_media; break; - case PCI_PRODUCT_LMC_T1: + case PCI_DEVICE_ID_LMC_T1: printk ("%s: LMC T1\n", dev->name); sc->lmc_cardtype = LMC_CARDTYPE_T1; sc->lmc_media = &lmc_t1_media; @@ -976,13 +967,13 @@ AdapModelNum = (lmc_mii_readreg (sc, 0, 3) & 0x3f0) >> 4; if ((AdapModelNum == LMC_ADAP_T1 - && subdevice == PCI_PRODUCT_LMC_T1) || /* detect LMC1200 */ + && subdevice == PCI_DEVICE_ID_LMC_T1) || /* detect LMC1200 */ (AdapModelNum == LMC_ADAP_SSI - && subdevice == PCI_PRODUCT_LMC_SSI) || /* detect LMC1000 */ + && subdevice == PCI_DEVICE_ID_LMC_SSI) || /* detect LMC1000 */ (AdapModelNum == LMC_ADAP_DS3 - && subdevice == PCI_PRODUCT_LMC_DS3) || /* detect LMC5245 */ + && subdevice == PCI_DEVICE_ID_LMC_DS3) || /* detect LMC5245 */ (AdapModelNum == LMC_ADAP_HSSI - && subdevice == PCI_PRODUCT_LMC_HSSI)) + && subdevice == PCI_DEVICE_ID_LMC_HSSI)) { /* detect LMC5200 */ } @@ -996,10 +987,7 @@ */ LMC_CSR_WRITE (sc, csr_gp_timer, 0xFFFFFFFFUL); - sc->board_idx = board_idx; - - memset (&sc->stats, 0, sizeof (struct lmc_statistics)); - + sc->board_idx = cards_found++; sc->stats.check = STATCHECK; sc->stats.version_size = (DRIVER_VERSION << 16) + sizeof (struct lmc_statistics); @@ -1008,105 +996,40 @@ sc->lmc_ok = 0; sc->last_link_status = 0; - lmc_trace(dev, "lmc_probe1 out"); - - return dev; -} - - -/* This is the entry point. This is what is called immediately. */ -/* This goes out and finds the card */ + lmc_trace(dev, "lmc_init_one out"); + return 0; -int lmc_probe_fake(struct net_device *dev) /*fold00*/ -{ - lmc_probe(NULL); - /* Return 1 to unloaded bogus device */ - return 1; + out4: + lmc_proto_detach(sc); + out3: + if (pdev) { + pci_release_regions(pdev); + pci_set_drvdata(pdev, NULL); + } + out2: + free_netdev(dev); + out1: + return err; } -int lmc_probe (struct net_device *dev) /*fold00*/ +/* + * Called from pci when removing module. + */ +static void __devexit lmc_remove_one (struct pci_dev *pdev) { - int pci_index = 0; - unsigned long pci_ioaddr; - unsigned int pci_irq_line; - u16 vendor, subvendor, device, subdevice; - u32 foundaddr = 0; - u8 intcf = 0; - struct pci_dev *pdev = NULL; - - /* Loop basically until we don't find anymore. */ - while ((pdev = pci_find_class (PCI_CLASS_NETWORK_ETHERNET << 8, pdev))) { - if (pci_enable_device(pdev)) - break; - - vendor = pdev->vendor; - device = pdev->device; - pci_irq_line = pdev->irq; - pci_ioaddr = pci_resource_start (pdev, 0); - subvendor = pdev->subsystem_vendor; - subdevice = pdev->subsystem_device; - - pci_set_master (pdev); - - /* - * Make sure it's the correct card. CHECK SUBVENDOR ID! - * There are lots of tulip's out there. - * Also check the region of registers we will soon be - * poking, to make sure no one else has reserved them. - * This prevents taking someone else's device. - * - * Check either the subvendor or the subdevice, some systems reverse - * the setting in the bois, seems to be version and arch dependent? - * Fix the two variables - * - */ - if (!(check_region (pci_ioaddr, LMC_REG_RANGE)) && - (vendor == CORRECT_VENDOR_ID) && - (device == CORRECT_DEV_ID) && - ((subvendor == PCI_VENDOR_LMC) || (subdevice == PCI_VENDOR_LMC))){ - struct net_device *cur, *prev = NULL; - - /* Fix the error, exchange the two values */ - if(subdevice == PCI_VENDOR_LMC){ - subdevice = subvendor; - subvendor = PCI_VENDOR_LMC ; - } - - /* Make the call to actually setup this card */ - dev = lmc_probe1 (dev, pci_ioaddr, pci_irq_line, - device, subdevice, cards_found); - if (dev == NULL) { - printk ("lmc_probe: lmc_probe1 failed\n"); - goto lmc_probe_next_card; - } - /* insert the device into the chain of lmc devices */ - for (cur = Lmc_root_dev; - cur != NULL; - cur = ((lmc_softc_t *) cur->priv)->next_module) { - prev = cur; - } - - if (prev == NULL) - Lmc_root_dev = dev; - else - ((lmc_softc_t *) prev->priv)->next_module = dev; - - ((lmc_softc_t *) dev->priv)->next_module = NULL; - /* end insert */ - - foundaddr = dev->base_addr; - - cards_found++; - intcf++; - } - lmc_probe_next_card: - pci_index++; + struct net_device *dev = pci_get_drvdata(pdev); + + if (dev) { + lmc_softc_t *sc = dev->priv; + + printk("%s: removing...\n", dev->name); + lmc_proto_detach(sc); + unregister_netdev(dev); + free_netdev(dev); + pci_release_regions(pdev); + pci_disable_device(pdev); + pci_set_drvdata(pdev, NULL); } - - if (cards_found < 1) - return -1; - - return foundaddr; } /* After this is called, packets can be sent. @@ -1181,8 +1104,6 @@ sc->stats.tx_tbusy0++ ; - MOD_INC_USE_COUNT; - /* * select what interrupts we want to get */ @@ -1352,7 +1273,6 @@ lmc_trace(dev, "lmc_ifdown out"); - MOD_DEC_USE_COUNT; return 0; } @@ -1850,12 +1770,11 @@ static struct net_device_stats *lmc_get_stats (struct net_device *dev) /*fold00*/ { - lmc_softc_t *sc; + lmc_softc_t *sc = dev->priv; unsigned long flags; lmc_trace(dev, "lmc_get_stats in"); - sc = dev->priv; spin_lock_irqsave(&sc->lmc_lock, flags); @@ -1868,58 +1787,21 @@ return (struct net_device_stats *) &sc->stats; } +static struct pci_driver lmc_driver = { + .name = "lmc", + .id_table = lmc_pci_tbl, + .probe = lmc_init_one, + .remove = __devexit_p(lmc_remove_one), +}; + static int __init init_lmc(void) { - printk ("lmc: module loaded\n"); - - /* Have lmc_probe search for all the cards, and allocate devices */ - if (lmc_probe (NULL) < 0) - return -EIO; - - return 0; + return pci_module_init(&lmc_driver); } static void __exit exit_lmc(void) { - struct net_device *dev, *next; - lmc_softc_t *sc; - - /* we have no pointer to our devices, since they are all dynamically - * allocated. So, here we loop through all the network devices - * looking for ours. When found, dispose of them properly. - */ - - for (dev = Lmc_root_dev; - dev != NULL; - dev = next ) - { - - next = ((lmc_softc_t *) dev->priv)->next_module; /* get it now before we deallocate it */ - printk ("%s: removing...\n", dev->name); - - /* close the syncppp stuff, and release irq. Close is run on unreg net */ - lmc_close (dev); - sc = dev->priv; - if (sc != NULL) - lmc_proto_detach(sc); - - /* Remove the device from the linked list */ - unregister_netdev (dev); - - /* Let go of the io region */; - release_region (dev->base_addr, LMC_REG_RANGE); - - /* free our allocated structures. */ - kfree (dev->priv); - dev->priv = NULL; - - free_netdev (dev); - dev = NULL; - } - - - Lmc_root_dev = NULL; - printk ("lmc module unloaded\n"); + pci_unregister_driver(&lmc_driver); } module_init(init_lmc); @@ -2326,8 +2208,3 @@ } - -int lmc_setup(void) { /*FOLD00*/ - return lmc_probe(NULL); -} - diff -Nru a/drivers/net/wan/lmc/lmc_var.h b/drivers/net/wan/lmc/lmc_var.h --- a/drivers/net/wan/lmc/lmc_var.h Thu Jan 22 18:59:25 2004 +++ b/drivers/net/wan/lmc/lmc_var.h Thu Jan 22 18:59:25 2004 @@ -390,7 +390,7 @@ struct timer_list timer; lmc_ctl_t ictl; u_int32_t TxDescriptControlInit; - struct net_device *next_module; /* Link to the next module */ + int tx_TimeoutInd; /* additional driver state */ int tx_TimeoutDisplay; unsigned int lastlmc_taint_tx; @@ -519,18 +519,7 @@ #define TULIP_CMD_RECEIVEALL 0x40000000L #endif - -/* PCI register values */ -#define CORRECT_VENDOR_ID 0x1011 -#define CORRECT_DEV_ID 9 - -#define PCI_VENDOR_LMC 0x1376 -#define PCI_PRODUCT_LMC_HSSI 0x0003 -#define PCI_PRODUCT_LMC_DS3 0x0004 -#define PCI_PRODUCT_LMC_SSI 0x0005 -#define PCI_PRODUCT_LMC_T1 0x0006 - -/* Adapcter module number */ +/* Adapter module number */ #define LMC_ADAP_HSSI 2 #define LMC_ADAP_DS3 3 #define LMC_ADAP_SSI 4 diff -Nru a/drivers/net/wan/n2.c b/drivers/net/wan/n2.c --- a/drivers/net/wan/n2.c Thu Jan 22 18:59:24 2004 +++ b/drivers/net/wan/n2.c Thu Jan 22 18:59:24 2004 @@ -92,7 +92,7 @@ typedef struct port_s { - hdlc_device hdlc; /* HDLC device struct - must be first */ + struct net_device *dev; struct card_s *card; spinlock_t lock; /* TX lock */ sync_serial_settings settings; @@ -215,13 +215,12 @@ static int n2_open(struct net_device *dev) { - hdlc_device *hdlc = dev_to_hdlc(dev); - port_t *port = hdlc_to_port(hdlc); + port_t *port = dev_to_port(dev); int io = port->card->io; u8 mcr = inb(io + N2_MCR) | (port->phy_node ? TX422_PORT1:TX422_PORT0); int result; - result = hdlc_open(hdlc); + result = hdlc_open(dev); if (result) return result; @@ -230,7 +229,7 @@ outb(inb(io + N2_PCR) | PCR_ENWIN, io + N2_PCR); /* open window */ outb(inb(io + N2_PSR) | PSR_DMAEN, io + N2_PSR); /* enable dma */ - sca_open(hdlc); + sca_open(dev); n2_set_iface(port); return 0; } @@ -239,15 +238,14 @@ static int n2_close(struct net_device *dev) { - hdlc_device *hdlc = dev_to_hdlc(dev); - port_t *port = hdlc_to_port(hdlc); + port_t *port = dev_to_port(dev); int io = port->card->io; u8 mcr = inb(io+N2_MCR) | (port->phy_node ? TX422_PORT1 : TX422_PORT0); - sca_close(hdlc); + sca_close(dev); mcr |= port->phy_node ? DTR_PORT1 : DTR_PORT0; /* set DTR OFF */ outb(mcr, io + N2_MCR); - hdlc_close(hdlc); + hdlc_close(dev); return 0; } @@ -257,12 +255,11 @@ { const size_t size = sizeof(sync_serial_settings); sync_serial_settings new_line, *line = ifr->ifr_settings.ifs_ifsu.sync; - hdlc_device *hdlc = dev_to_hdlc(dev); - port_t *port = hdlc_to_port(hdlc); + port_t *port = dev_to_port(dev); #ifdef DEBUG_RINGS if (cmd == SIOCDEVPRIVATE) { - sca_dump_rings(hdlc); + sca_dump_rings(dev); return 0; } #endif @@ -312,8 +309,10 @@ int cnt; for (cnt = 0; cnt < 2; cnt++) - if (card->ports[cnt].card) - unregister_hdlc_device(&card->ports[cnt].hdlc); + if (card->ports[cnt].card) { + struct net_device *dev = port_to_dev(&card->ports[cnt]); + unregister_hdlc_device(dev); + } if (card->irq) free_irq(card->irq, card); @@ -325,6 +324,10 @@ if (card->io) release_region(card->io, N2_IOPORTS); + if (card->ports[0].dev) + free_netdev(card->ports[0].dev); + if (card->ports[1].dev) + free_netdev(card->ports[1].dev); kfree(card); } @@ -359,6 +362,14 @@ } memset(card, 0, sizeof(card_t)); + card->ports[0].dev = alloc_hdlcdev(&card->ports[0]); + card->ports[1].dev = alloc_hdlcdev(&card->ports[1]); + if (!card->ports[0].dev || !card->ports[1].dev) { + printk(KERN_ERR "n2: unable to allocate memory\n"); + n2_destroy_card(card); + return -ENOMEM; + } + if (!request_region(io, N2_IOPORTS, devname)) { printk(KERN_ERR "n2: I/O port region in use\n"); n2_destroy_card(card); @@ -435,7 +446,8 @@ sca_init(card, 0); for (cnt = 0; cnt < 2; cnt++) { port_t *port = &card->ports[cnt]; - struct net_device *dev = hdlc_to_dev(&port->hdlc); + struct net_device *dev = port_to_dev(port); + hdlc_device *hdlc = dev_to_hdlc(dev); if ((cnt == 0 && !valid0) || (cnt == 1 && !valid1)) continue; @@ -455,21 +467,22 @@ dev->do_ioctl = n2_ioctl; dev->open = n2_open; dev->stop = n2_close; - port->hdlc.attach = sca_attach; - port->hdlc.xmit = sca_xmit; + hdlc->attach = sca_attach; + hdlc->xmit = sca_xmit; port->settings.clock_type = CLOCK_EXT; + port->card = card; - if (register_hdlc_device(&port->hdlc)) { + if (register_hdlc_device(dev)) { printk(KERN_WARNING "n2: unable to register hdlc " "device\n"); + port->card = NULL; n2_destroy_card(card); return -ENOBUFS; } - port->card = card; sca_init_sync_port(port); /* Set up SCA memory */ printk(KERN_INFO "%s: RISCom/N2 node %d\n", - hdlc_to_name(&port->hdlc), port->phy_node); + dev->name, port->phy_node); } *new_card = card; diff -Nru a/drivers/net/wan/pc300.h b/drivers/net/wan/pc300.h --- a/drivers/net/wan/pc300.h Thu Jan 22 18:59:24 2004 +++ b/drivers/net/wan/pc300.h Thu Jan 22 18:59:24 2004 @@ -331,7 +331,7 @@ uclong line_off; #ifdef __KERNEL__ char name[16]; - hdlc_device *hdlc; + struct net_device *dev; void *private; struct sk_buff *tx_skb; @@ -483,7 +483,7 @@ void tx_dma_stop(pc300_t *, int); void rx_dma_stop(pc300_t *, int); int cpc_queue_xmit(struct sk_buff *, struct net_device *); -void cpc_net_rx(hdlc_device *); +void cpc_net_rx(struct net_device *); void cpc_sca_status(pc300_t *, int); int cpc_change_mtu(struct net_device *, int); int cpc_ioctl(struct net_device *, struct ifreq *, int); diff -Nru a/drivers/net/wan/pc300_drv.c b/drivers/net/wan/pc300_drv.c --- a/drivers/net/wan/pc300_drv.c Thu Jan 22 18:59:26 2004 +++ b/drivers/net/wan/pc300_drv.c Thu Jan 22 18:59:26 2004 @@ -290,7 +290,7 @@ static uclong detect_ram(pc300_t *); static void plx_init(pc300_t *); static void cpc_trace(struct net_device *, struct sk_buff *, char); -static int cpc_attach(hdlc_device *, unsigned short, unsigned short); +static int cpc_attach(struct net_device *, unsigned short, unsigned short); #ifdef CONFIG_PC300_MLPPP void cpc_tty_init(pc300dev_t * dev); @@ -1774,7 +1774,7 @@ pc300dev_t *d = (pc300dev_t *) dev->priv; pc300ch_t *chan = (pc300ch_t *) d->chan; pc300_t *card = (pc300_t *) chan->card; - struct net_device_stats *stats = &d->hdlc->stats; + struct net_device_stats *stats = hdlc_stats(dev); int ch = chan->channel; uclong flags; ucchar ilar; @@ -1802,7 +1802,7 @@ pc300dev_t *d = (pc300dev_t *) dev->priv; pc300ch_t *chan = (pc300ch_t *) d->chan; pc300_t *card = (pc300_t *) chan->card; - struct net_device_stats *stats = &d->hdlc->stats; + struct net_device_stats *stats = hdlc_stats(dev); int ch = chan->channel; uclong flags; #ifdef PC300_DEBUG_TX @@ -1880,13 +1880,12 @@ return 0; } -void cpc_net_rx(hdlc_device * hdlc) +void cpc_net_rx(struct net_device *dev) { - struct net_device *dev = hdlc_to_dev(hdlc); pc300dev_t *d = (pc300dev_t *) dev->priv; pc300ch_t *chan = (pc300ch_t *) d->chan; pc300_t *card = (pc300_t *) chan->card; - struct net_device_stats *stats = &d->hdlc->stats; + struct net_device_stats *stats = hdlc_stats(dev); int ch = chan->channel; #ifdef PC300_DEBUG_RX int i; @@ -1975,7 +1974,7 @@ pc300_t *card = (pc300_t *)chan->card; int ch = chan->channel; volatile pcsca_bd_t * ptdescr; - struct net_device_stats *stats = &dev->hdlc->stats; + struct net_device_stats *stats = hdlc_stats(dev->dev); /* Clean up descriptors from previous transmission */ ptdescr = (pcsca_bd_t *)(card->hw.rambase + @@ -1999,7 +1998,7 @@ } else { #endif /* Tell the upper layer we are ready to transmit more packets */ - netif_wake_queue((struct net_device*)dev->hdlc); + netif_wake_queue(dev->dev); #ifdef CONFIG_PC300_MLPPP } #endif @@ -2017,8 +2016,8 @@ for (ch = 0; ch < card->hw.nchan; ch++) { pc300ch_t *chan = &card->chan[ch]; pc300dev_t *d = &chan->d; - hdlc_device *hdlc = d->hdlc; - struct net_device *dev = hdlc_to_dev(hdlc); + struct net_device *dev = d->dev; + hdlc_device *hdlc = dev_to_hdlc(dev); spin_lock(&card->card_lock); @@ -2049,7 +2048,7 @@ if ((cpc_readb(scabase + DSR_RX(ch)) & DSR_DE)) { rx_dma_stop(card, ch); } - cpc_net_rx(hdlc); + cpc_net_rx(dev); /* Discard invalid frames */ hdlc->stats.rx_errors++; hdlc->stats.rx_over_errors++; @@ -2073,10 +2072,10 @@ /* verify if driver is TTY */ cpc_tty_receive(d); } else { - cpc_net_rx(hdlc); + cpc_net_rx(dev); } #else - cpc_net_rx(hdlc); + cpc_net_rx(dev); #endif if (card->hw.type == PC300_TE) { cpc_writeb(card->hw.falcbase + @@ -2818,12 +2817,7 @@ static struct net_device_stats *cpc_get_stats(struct net_device *dev) { - pc300dev_t *d = (pc300dev_t *) dev->priv; - - if (d) - return &d->hdlc->stats; - else - return NULL; + return hdlc_stats(dev); } static int clock_rate_calc(uclong rate, uclong clock, int *br_io) @@ -3064,10 +3058,9 @@ return 0; } -static int cpc_attach(hdlc_device * hdlc, unsigned short encoding, +static int cpc_attach(struct net_device *dev, unsigned short encoding, unsigned short parity) { - struct net_device * dev = hdlc_to_dev(hdlc); pc300dev_t *d = (pc300dev_t *)dev->priv; pc300ch_t *chan = (pc300ch_t *)d->chan; pc300_t *card = (pc300_t *)chan->card; @@ -3157,7 +3150,7 @@ d->if_ptr = &hdlc->state.ppp.pppdev; } - result = hdlc_open(hdlc); + result = hdlc_open(dev); if (hdlc->proto.id == IF_PROTO_PPP) { dev->priv = d; } @@ -3189,7 +3182,7 @@ cpc_closech(d); CPC_UNLOCK(card, flags); - hdlc_close(hdlc); + hdlc_close(dev); if (hdlc->proto.id == IF_PROTO_PPP) { d->if_ptr = NULL; } @@ -3358,17 +3351,14 @@ d->line_on = 0; d->line_off = 0; - d->hdlc = (hdlc_device *) kmalloc(sizeof(hdlc_device), GFP_KERNEL); - if (d->hdlc == NULL) + dev = alloc_hdlcdev(NULL); + if (dev == NULL) continue; - memset(d->hdlc, 0, sizeof(hdlc_device)); - hdlc = d->hdlc; + hdlc = dev_to_hdlc(dev); hdlc->xmit = cpc_queue_xmit; hdlc->attach = cpc_attach; - - dev = hdlc_to_dev(hdlc); - + d->dev = dev; dev->mem_start = card->hw.ramphys; dev->mem_end = card->hw.ramphys + card->hw.ramsize - 1; dev->irq = card->hw.irq; @@ -3386,7 +3376,7 @@ dev->change_mtu = cpc_change_mtu; dev->do_ioctl = cpc_ioctl; - if (register_hdlc_device(hdlc) == 0) { + if (register_hdlc_device(dev) == 0) { dev->priv = d; /* We need 'priv', hdlc doesn't */ printk("%s: Cyclades-PC300/", dev->name); switch (card->hw.type) { @@ -3414,8 +3404,7 @@ } else { printk ("Dev%d on card(0x%08lx): unable to allocate i/f name.\n", i + 1, card->hw.ramphys); - *(dev->name) = 0; - kfree(d->hdlc); + free_netdev(dev); continue; } } @@ -3647,7 +3636,7 @@ cpc_readw(card->hw.plxbase + card->hw.intctl_reg) & ~(0x0040)); for (i = 0; i < card->hw.nchan; i++) { - unregister_hdlc_device(card->chan[i].d.hdlc); + unregister_hdlc_device(card->chan[i].d.dev); } iounmap((void *) card->hw.plxbase); iounmap((void *) card->hw.scabase); @@ -3660,6 +3649,9 @@ iounmap((void *) card->hw.falcbase); release_mem_region(card->hw.falcphys, card->hw.falcsize); } + for (i = 0; i < card->hw.nchan; i++) + if (card->chan[i].d.dev); + free_netdev(card->chan[i].d.dev); if (card->hw.irq) free_irq(card->hw.irq, card); kfree(card); diff -Nru a/drivers/net/wan/pc300_tty.c b/drivers/net/wan/pc300_tty.c --- a/drivers/net/wan/pc300_tty.c Thu Jan 22 18:59:25 2004 +++ b/drivers/net/wan/pc300_tty.c Thu Jan 22 18:59:25 2004 @@ -152,8 +152,7 @@ int ch = pc300chan->channel; unsigned long flags; - CPC_TTY_DBG("%s-tty: Clear signal DTR\n", - ((struct net_device*)(pc300dev->hdlc))->name); + CPC_TTY_DBG("%s-tty: Clear signal DTR\n", pc300dev->dev->name); CPC_TTY_LOCK(card, flags); cpc_writeb(card->hw.scabase + M_REG(CTL,ch), cpc_readb(card->hw.scabase+M_REG(CTL,ch))& CTL_DTR); @@ -170,8 +169,7 @@ int ch = pc300chan->channel; unsigned long flags; - CPC_TTY_DBG("%s-tty: Set signal DTR\n", - ((struct net_device*)(pc300dev->hdlc))->name); + CPC_TTY_DBG("%s-tty: Set signal DTR\n", pc300dev->dev->name); CPC_TTY_LOCK(card, flags); cpc_writeb(card->hw.scabase + M_REG(CTL,ch), cpc_readb(card->hw.scabase+M_REG(CTL,ch))& ~CTL_DTR); @@ -194,17 +192,17 @@ st_cpc_tty_area * cpc_tty; /* hdlcX - X=interface number */ - port = ((struct net_device*)(pc300dev->hdlc))->name[4] - '0'; + port = pc300dev->dev->name[4] - '0'; if (port >= CPC_TTY_NPORTS) { printk("%s-tty: invalid interface selected (0-%i): %i", - ((struct net_device*)(pc300dev->hdlc))->name, + pc300dev->dev->name, CPC_TTY_NPORTS-1,port); return; } if (cpc_tty_cnt == 0) { /* first TTY connection -> register driver */ CPC_TTY_DBG("%s-tty: driver init, major:%i, minor range:%i=%i\n", - ((struct net_device*)(pc300dev->hdlc))->name, + pc300dev->dev->name, CPC_TTY_MAJOR, CPC_TTY_MINOR_START, CPC_TTY_MINOR_START+CPC_TTY_NPORTS); /* initialize tty driver struct */ @@ -236,7 +234,7 @@ /* register the TTY driver */ if (tty_register_driver(&serial_drv)) { printk("%s-tty: Failed to register serial driver! ", - ((struct net_device*)(pc300dev->hdlc))->name); + pc300dev->dev->name); return; } @@ -248,7 +246,7 @@ if (cpc_tty->state != CPC_TTY_ST_IDLE) { CPC_TTY_DBG("%s-tty: TTY port %i, already in use.\n", - ((struct net_device*)(pc300dev->hdlc))->name,port); + pc300dev->dev->name, port); return; } @@ -265,11 +263,11 @@ pc300dev->cpc_tty = (void *)cpc_tty; - aux = strlen(((struct net_device*)(pc300dev->hdlc))->name); - memcpy(cpc_tty->name,((struct net_device*)(pc300dev->hdlc))->name,aux); + aux = strlen(pc300dev->dev->name); + memcpy(cpc_tty->name, pc300dev->dev->name, aux); memcpy(&cpc_tty->name[aux], "-tty", 5); - cpc_open((struct net_device *)pc300dev->hdlc); + cpc_open(pc300dev->dev); cpc_tty_dtr_off(pc300dev); CPC_TTY_DBG("%s: Initializing TTY Sync Driver, tty major#%d minor#%i\n", @@ -454,7 +452,7 @@ (from_user)?"from user" : "from kernel",count); pc300chan = (pc300ch_t *)((pc300dev_t*)cpc_tty->pc300dev)->chan; - stats = &((pc300dev_t*)cpc_tty->pc300dev)->hdlc->stats; + stats = hdlc_stats(((pc300dev_t*)cpc_tty->pc300dev)->dev); card = (pc300_t *) pc300chan->card; ch = pc300chan->channel; @@ -740,7 +738,7 @@ pc300_t *card = (pc300_t *)pc300chan->card; int ch = pc300chan->channel; volatile pcsca_bd_t * ptdescr; - struct net_device_stats *stats = &pc300dev->hdlc->stats; + struct net_device_stats *stats = hdlc_stats(pc300dev->dev); int rx_len, rx_aux; volatile unsigned char status; unsigned short first_bd = pc300chan->rx_first_bd; @@ -916,7 +914,7 @@ pc300ch_t *chan = (pc300ch_t *)dev->chan; pc300_t *card = (pc300_t *)chan->card; int ch = chan->channel; - struct net_device_stats *stats = &dev->hdlc->stats; + struct net_device_stats *stats = hdlc_stats(dev->dev); unsigned long flags; volatile pcsca_bd_t * ptdescr; int i, nchar; @@ -1000,19 +998,18 @@ if ((skb = dev_alloc_skb(10 + len)) == NULL) { /* out of memory */ - CPC_TTY_DBG("%s: tty_trace - out of memory\n", - ((struct net_device *)(dev->hdlc))->name); + CPC_TTY_DBG("%s: tty_trace - out of memory\n", dev->dev->name); return; } skb_put (skb, 10 + len); - skb->dev = (struct net_device *) dev->hdlc; + skb->dev = dev->dev; skb->protocol = htons(ETH_P_CUST); skb->mac.raw = skb->data; skb->pkt_type = PACKET_HOST; skb->len = 10 + len; - memcpy(skb->data,((struct net_device *)(dev->hdlc))->name,5); + memcpy(skb->data,dev->dev->name,5); skb->data[5] = '['; skb->data[6] = rxtx; skb->data[7] = ']'; @@ -1034,15 +1031,14 @@ int res; if ((cpc_tty= (st_cpc_tty_area *) pc300dev->cpc_tty) == 0) { - CPC_TTY_DBG("%s: interface is not TTY\n", - ((struct net_device *)(pc300dev->hdlc))->name); + CPC_TTY_DBG("%s: interface is not TTY\n", pc300dev->dev->name); return; } CPC_TTY_DBG("%s: cpc_tty_unregister_service", cpc_tty->name); if (cpc_tty->pc300dev != pc300dev) { CPC_TTY_DBG("%s: invalid tty ptr=%s\n", - ((struct net_device *)(pc300dev->hdlc))->name, cpc_tty->name); + pc300dev->dev->name, cpc_tty->name); return; } diff -Nru a/drivers/net/wan/pci200syn.c b/drivers/net/wan/pci200syn.c --- a/drivers/net/wan/pci200syn.c Thu Jan 22 18:59:24 2004 +++ b/drivers/net/wan/pci200syn.c Thu Jan 22 18:59:24 2004 @@ -73,7 +73,7 @@ typedef struct port_s { - hdlc_device hdlc; /* HDLC device struct - must be first */ + struct net_device *dev; struct card_s *card; spinlock_t lock; /* TX lock */ sync_serial_settings settings; @@ -177,14 +177,13 @@ static int pci200_open(struct net_device *dev) { - hdlc_device *hdlc = dev_to_hdlc(dev); - port_t *port = hdlc_to_port(hdlc); + port_t *port = dev_to_port(dev); - int result = hdlc_open(hdlc); + int result = hdlc_open(dev); if (result) return result; - sca_open(hdlc); + sca_open(dev); pci200_set_iface(port); sca_flush(port_to_card(port)); return 0; @@ -194,10 +193,9 @@ static int pci200_close(struct net_device *dev) { - hdlc_device *hdlc = dev_to_hdlc(dev); - sca_close(hdlc); + sca_close(dev); sca_flush(port_to_card(dev_to_port(dev))); - hdlc_close(hdlc); + hdlc_close(dev); return 0; } @@ -207,12 +205,11 @@ { const size_t size = sizeof(sync_serial_settings); sync_serial_settings new_line, *line = ifr->ifr_settings.ifs_ifsu.sync; - hdlc_device *hdlc = dev_to_hdlc(dev); - port_t *port = hdlc_to_port(hdlc); + port_t *port = dev_to_port(dev); #ifdef DEBUG_RINGS if (cmd == SIOCDEVPRIVATE) { - sca_dump_rings(hdlc); + sca_dump_rings(dev); return 0; } #endif @@ -265,8 +262,10 @@ card_t *card = pci_get_drvdata(pdev); for(i = 0; i < 2; i++) - if (card->ports[i].card) - unregister_hdlc_device(&card->ports[i].hdlc); + if (card->ports[i].card) { + struct net_device *dev = port_to_dev(&card->ports[i]); + unregister_hdlc_device(dev); + } if (card->irq) free_irq(card->irq, card); @@ -281,6 +280,10 @@ pci_release_regions(pdev); pci_disable_device(pdev); pci_set_drvdata(pdev, NULL); + if (card->ports[0].dev) + free_netdev(card->ports[0].dev); + if (card->ports[1].dev) + free_netdev(card->ports[1].dev); kfree(card); } @@ -323,6 +326,13 @@ } memset(card, 0, sizeof(card_t)); pci_set_drvdata(pdev, card); + card->ports[0].dev = alloc_hdlcdev(&card->ports[0]); + card->ports[1].dev = alloc_hdlcdev(&card->ports[1]); + if (!card->ports[0].dev || !card->ports[1].dev) { + printk(KERN_ERR "pci200syn: unable to allocate memory\n"); + pci200_pci_remove_one(pdev); + return -ENOMEM; + } pci_read_config_byte(pdev, PCI_REVISION_ID, &rev_id); if (pci_resource_len(pdev, 0) != PCI200SYN_PLX_SIZE || @@ -397,7 +407,8 @@ for(i = 0; i < 2; i++) { port_t *port = &card->ports[i]; - struct net_device *dev = hdlc_to_dev(&port->hdlc); + struct net_device *dev = port_to_dev(port); + hdlc_device *hdlc = dev_to_hdlc(dev); port->phy_node = i; spin_lock_init(&port->lock); @@ -409,20 +420,21 @@ dev->do_ioctl = pci200_ioctl; dev->open = pci200_open; dev->stop = pci200_close; - port->hdlc.attach = sca_attach; - port->hdlc.xmit = sca_xmit; + hdlc->attach = sca_attach; + hdlc->xmit = sca_xmit; port->settings.clock_type = CLOCK_EXT; - if(register_hdlc_device(&port->hdlc)) { + port->card = card; + if(register_hdlc_device(dev)) { printk(KERN_ERR "pci200syn: unable to register hdlc " "device\n"); + port->card = NULL; pci200_pci_remove_one(pdev); return -ENOBUFS; } - port->card = card; sca_init_sync_port(port); /* Set up SCA memory */ printk(KERN_INFO "%s: PCI200SYN node %d\n", - hdlc_to_name(&port->hdlc), port->phy_node); + dev->name, port->phy_node); } sca_flush(card); diff -Nru a/drivers/net/wan/sbni.c b/drivers/net/wan/sbni.c --- a/drivers/net/wan/sbni.c Thu Jan 22 18:59:24 2004 +++ b/drivers/net/wan/sbni.c Thu Jan 22 18:59:24 2004 @@ -210,7 +210,6 @@ static void __init sbni_devsetup(struct net_device *dev) { ether_setup( dev ); - dev->init = &sbni_init; dev->open = &sbni_open; dev->stop = &sbni_close; dev->hard_start_xmit = &sbni_start_xmit; @@ -234,8 +233,15 @@ sprintf(dev->name, "sbni%d", unit); netdev_boot_setup_check(dev); + err = sbni_init(dev); + if (err) { + free_netdev(dev); + return err; + } + err = register_netdev(dev); if (err) { + release_region( dev->base_addr, SBNI_IO_EXTENT ); free_netdev(dev); return err; } @@ -304,8 +310,13 @@ /* Avoid already found cards from previous calls */ if( !request_region( pci_ioaddr, SBNI_IO_EXTENT, dev->name ) ) { pci_read_config_word( pdev, PCI_SUBSYSTEM_ID, &subsys ); - if( subsys != 2 || /* Dual adapter is present */ - check_region( pci_ioaddr += 4, SBNI_IO_EXTENT ) ) + + if (subsys != 2) + continue; + + /* Dual adapter is present */ + if (!request_region(pci_ioaddr += 4, SBNI_IO_EXTENT, + dev->name ) ) continue; } @@ -318,8 +329,10 @@ pci_irq_line ); /* avoiding re-enable dual adapters */ - if( (pci_ioaddr & 7) == 0 && pci_enable_device( pdev ) ) + if( (pci_ioaddr & 7) == 0 && pci_enable_device( pdev ) ) { + release_region( pci_ioaddr, SBNI_IO_EXTENT ); return -EIO; + } if( sbni_probe1( dev, pci_ioaddr, pci_irq_line ) ) return 0; } @@ -1482,19 +1495,25 @@ init_module( void ) { struct net_device *dev; + int err; while( num < SBNI_MAX_NUM_CARDS ) { dev = alloc_netdev(sizeof(struct net_local), "sbni%d", sbni_devsetup); - if( !dev) { - printk( KERN_ERR "sbni: unable to allocate device!\n" ); - return -ENOMEM; - } + if( !dev) + break; sprintf( dev->name, "sbni%d", num ); + err = sbni_init(dev); + if (err) { + free_netdev(dev); + break; + } + if( register_netdev( dev ) ) { - kfree( dev ); + release_region( dev->base_addr, SBNI_IO_EXTENT ); + free_netdev( dev ); break; } } diff -Nru a/drivers/net/wan/sdla.c b/drivers/net/wan/sdla.c --- a/drivers/net/wan/sdla.c Thu Jan 22 18:59:27 2004 +++ b/drivers/net/wan/sdla.c Thu Jan 22 18:59:27 2004 @@ -1339,6 +1339,8 @@ struct frad_local *flp; int i; char byte; + unsigned base; + int err = -EINVAL; flp = dev->priv; @@ -1352,108 +1354,90 @@ if (i == sizeof(valid_port) / sizeof(int)) return(-EINVAL); - dev->base_addr = map->base_addr; - if (!request_region(dev->base_addr, SDLA_IO_EXTENTS, dev->name)){ + if (!request_region(map->base_addr, SDLA_IO_EXTENTS, dev->name)){ printk(KERN_WARNING "SDLA: io-port 0x%04lx in use \n", dev->base_addr); return(-EINVAL); } + base = map->base_addr; + /* test for card types, S502A, S502E, S507, S508 */ /* these tests shut down the card completely, so clear the state */ flp->type = SDLA_UNKNOWN; flp->state = 0; for(i=1;ibase_addr + i) != 0xFF) + if (inb(base + i) != 0xFF) break; - if (i == SDLA_IO_EXTENTS) - { - outb(SDLA_HALT, dev->base_addr + SDLA_REG_Z80_CONTROL); - if ((inb(dev->base_addr + SDLA_S502_STS) & 0x0F) == 0x08) - { - outb(SDLA_S502E_INTACK, dev->base_addr + SDLA_REG_CONTROL); - if ((inb(dev->base_addr + SDLA_S502_STS) & 0x0F) == 0x0C) - { - outb(SDLA_HALT, dev->base_addr + SDLA_REG_CONTROL); + if (i == SDLA_IO_EXTENTS) { + outb(SDLA_HALT, base + SDLA_REG_Z80_CONTROL); + if ((inb(base + SDLA_S502_STS) & 0x0F) == 0x08) { + outb(SDLA_S502E_INTACK, base + SDLA_REG_CONTROL); + if ((inb(base + SDLA_S502_STS) & 0x0F) == 0x0C) { + outb(SDLA_HALT, base + SDLA_REG_CONTROL); flp->type = SDLA_S502E; + goto got_type; } } } - if (flp->type == SDLA_UNKNOWN) - { - for(byte=inb(dev->base_addr),i=0;ibase_addr + i) != byte) - break; + for(byte=inb(base),i=0;ibase_addr + SDLA_REG_CONTROL); - if ((inb(dev->base_addr + SDLA_S502_STS) & 0x7E) == 0x30) - { - outb(SDLA_S507_ENABLE, dev->base_addr + SDLA_REG_CONTROL); - if ((inb(dev->base_addr + SDLA_S502_STS) & 0x7E) == 0x32) - { - outb(SDLA_HALT, dev->base_addr + SDLA_REG_CONTROL); - flp->type = SDLA_S507; - } + if (i == SDLA_IO_EXTENTS) { + outb(SDLA_HALT, base + SDLA_REG_CONTROL); + if ((inb(base + SDLA_S502_STS) & 0x7E) == 0x30) { + outb(SDLA_S507_ENABLE, base + SDLA_REG_CONTROL); + if ((inb(base + SDLA_S502_STS) & 0x7E) == 0x32) { + outb(SDLA_HALT, base + SDLA_REG_CONTROL); + flp->type = SDLA_S507; + goto got_type; } } } - if (flp->type == SDLA_UNKNOWN) - { - outb(SDLA_HALT, dev->base_addr + SDLA_REG_CONTROL); - if ((inb(dev->base_addr + SDLA_S508_STS) & 0x3F) == 0x00) - { - outb(SDLA_S508_INTEN, dev->base_addr + SDLA_REG_CONTROL); - if ((inb(dev->base_addr + SDLA_S508_STS) & 0x3F) == 0x10) - { - outb(SDLA_HALT, dev->base_addr + SDLA_REG_CONTROL); - flp->type = SDLA_S508; - } + outb(SDLA_HALT, base + SDLA_REG_CONTROL); + if ((inb(base + SDLA_S508_STS) & 0x3F) == 0x00) { + outb(SDLA_S508_INTEN, base + SDLA_REG_CONTROL); + if ((inb(base + SDLA_S508_STS) & 0x3F) == 0x10) { + outb(SDLA_HALT, base + SDLA_REG_CONTROL); + flp->type = SDLA_S508; + goto got_type; } } - if (flp->type == SDLA_UNKNOWN) - { - outb(SDLA_S502A_HALT, dev->base_addr + SDLA_REG_CONTROL); - if (inb(dev->base_addr + SDLA_S502_STS) == 0x40) - { - outb(SDLA_S502A_START, dev->base_addr + SDLA_REG_CONTROL); - if (inb(dev->base_addr + SDLA_S502_STS) == 0x40) - { - outb(SDLA_S502A_INTEN, dev->base_addr + SDLA_REG_CONTROL); - if (inb(dev->base_addr + SDLA_S502_STS) == 0x44) - { - outb(SDLA_S502A_START, dev->base_addr + SDLA_REG_CONTROL); - flp->type = SDLA_S502A; - } + outb(SDLA_S502A_HALT, base + SDLA_REG_CONTROL); + if (inb(base + SDLA_S502_STS) == 0x40) { + outb(SDLA_S502A_START, base + SDLA_REG_CONTROL); + if (inb(base + SDLA_S502_STS) == 0x40) { + outb(SDLA_S502A_INTEN, base + SDLA_REG_CONTROL); + if (inb(base + SDLA_S502_STS) == 0x44) { + outb(SDLA_S502A_START, base + SDLA_REG_CONTROL); + flp->type = SDLA_S502A; + goto got_type; } } } - if (flp->type == SDLA_UNKNOWN) - { - printk(KERN_NOTICE "%s: Unknown card type\n", dev->name); - return(-ENODEV); - } + printk(KERN_NOTICE "%s: Unknown card type\n", dev->name); + err = -ENODEV; + goto fail; - switch(dev->base_addr) - { +got_type: + switch(base) { case 0x270: case 0x280: case 0x380: case 0x390: - if ((flp->type != SDLA_S508) && (flp->type != SDLA_S507)) - return(-EINVAL); + if (flp->type != SDLA_S508 && flp->type != SDLA_S507) + goto fail; } - switch (map->irq) - { + switch (map->irq) { case 2: if (flp->type != SDLA_S502E) - return(-EINVAL); + goto fail; break; case 10: @@ -1461,28 +1445,26 @@ case 12: case 15: case 4: - if ((flp->type != SDLA_S508) && (flp->type != SDLA_S507)) - return(-EINVAL); - + if (flp->type != SDLA_S508 && flp->type != SDLA_S507) + goto fail; + break; case 3: case 5: case 7: if (flp->type == SDLA_S502A) - return(-EINVAL); + goto fail; break; default: - return(-EINVAL); + goto fail; } - dev->irq = map->irq; + err = -EAGAIN; if (request_irq(dev->irq, &sdla_isr, 0, dev->name, dev)) - return(-EAGAIN); + goto fail; - if (flp->type == SDLA_S507) - { - switch(dev->irq) - { + if (flp->type == SDLA_S507) { + switch(dev->irq) { case 3: flp->state = SDLA_S507_IRQ3; break; @@ -1514,35 +1496,25 @@ if (valid_mem[i] == map->mem_start) break; + err = -EINVAL; if (i == sizeof(valid_mem) / sizeof(int)) - /* - * FIXME: - * BUG BUG BUG: MUST RELEASE THE IRQ WE ALLOCATED IN - * ALL THESE CASES - * - */ - return(-EINVAL); + goto fail2; - if ((flp->type == SDLA_S502A) && (((map->mem_start & 0xF000) >> 12) == 0x0E)) - return(-EINVAL); - - if ((flp->type != SDLA_S507) && ((map->mem_start >> 16) == 0x0B)) - return(-EINVAL); + if (flp->type == SDLA_S502A && (map->mem_start & 0xF000) >> 12 == 0x0E) + goto fail2; - if ((flp->type == SDLA_S507) && ((map->mem_start >> 16) == 0x0D)) - return(-EINVAL); + if (flp->type != SDLA_S507 && map->mem_start >> 16 == 0x0B) + goto fail2; - dev->mem_start = map->mem_start; - dev->mem_end = dev->mem_start + 0x2000; + if (flp->type == SDLA_S507 && map->mem_start >> 16 == 0x0D) + goto fail2; byte = flp->type != SDLA_S508 ? SDLA_8K_WINDOW : 0; byte |= (map->mem_start & 0xF000) >> (12 + (flp->type == SDLA_S508 ? 1 : 0)); - switch(flp->type) - { + switch(flp->type) { case SDLA_S502A: case SDLA_S502E: - switch (map->mem_start >> 16) - { + switch (map->mem_start >> 16) { case 0x0A: byte |= SDLA_S502_SEG_A; break; @@ -1558,8 +1530,7 @@ } break; case SDLA_S507: - switch (map->mem_start >> 16) - { + switch (map->mem_start >> 16) { case 0x0A: byte |= SDLA_S507_SEG_A; break; @@ -1575,8 +1546,7 @@ } break; case SDLA_S508: - switch (map->mem_start >> 16) - { + switch (map->mem_start >> 16) { case 0x0A: byte |= SDLA_S508_SEG_A; break; @@ -1594,7 +1564,7 @@ } /* set the memory bits, and enable access */ - outb(byte, dev->base_addr + SDLA_REG_PC_WINDOW); + outb(byte, base + SDLA_REG_PC_WINDOW); switch(flp->type) { @@ -1608,10 +1578,20 @@ flp->state = SDLA_MEMEN; break; } - outb(flp->state, dev->base_addr + SDLA_REG_CONTROL); + outb(flp->state, base + SDLA_REG_CONTROL); + dev->irq = map->irq; + dev->base_addr = base; + dev->mem_start = map->mem_start; + dev->mem_end = dev->mem_start + 0x2000; flp->initialized = 1; - return(0); + return 0; + +fail2: + free_irq(map->irq, dev); +fail: + release_region(base, SDLA_IO_EXTENTS); + return err; } static struct net_device_stats *sdla_stats(struct net_device *dev) @@ -1676,13 +1656,13 @@ static void __exit exit_sdla(void) { - struct frad_local *flp; + struct frad_local *flp = sdla->priv; unregister_netdev(sdla); - if (sdla->irq) + if (flp->initialized) { free_irq(sdla->irq, sdla); - - flp = sdla->priv; + release_region(sdla->base_addr, SDLA_IO_EXTENTS); + } del_timer_sync(&flp->timer); free_netdev(sdla); } diff -Nru a/drivers/net/wan/sealevel.c b/drivers/net/wan/sealevel.c --- a/drivers/net/wan/sealevel.c Thu Jan 22 18:59:25 2004 +++ b/drivers/net/wan/sealevel.c Thu Jan 22 18:59:25 2004 @@ -420,6 +420,7 @@ /* DMA off on the card, drop DTR */ outb(0, b->iobase); release_region(b->iobase, 8); + kfree(b); } diff -Nru a/drivers/net/wan/wanxl.c b/drivers/net/wan/wanxl.c --- a/drivers/net/wan/wanxl.c Thu Jan 22 18:59:26 2004 +++ b/drivers/net/wan/wanxl.c Thu Jan 22 18:59:26 2004 @@ -51,7 +51,7 @@ typedef struct { - hdlc_device hdlc; /* HDLC device struct - must be first */ + struct net_device *dev; struct card_t *card; spinlock_t lock; /* for wanxl_xmit */ int node; /* physical port #0 - 3 */ @@ -78,31 +78,26 @@ struct sk_buff *rx_skbs[RX_QUEUE_LENGTH]; card_status_t *status; /* shared between host and card */ dma_addr_t status_address; + port_t __ports[0]; }card_t; -static inline port_t* hdlc_to_port(hdlc_device *hdlc) -{ - return (port_t*)hdlc; -} - - static inline port_t* dev_to_port(struct net_device *dev) { - return hdlc_to_port(dev_to_hdlc(dev)); + return (port_t *)dev_to_hdlc(dev)->priv; } static inline struct net_device *port_to_dev(port_t* port) { - return hdlc_to_dev(&port->hdlc); + return port->dev; } static inline const char* port_name(port_t *port) { - return hdlc_to_name((hdlc_device*)port); + return port_to_dev(port)->name; } @@ -172,7 +167,7 @@ printk(KERN_INFO "%s: %s%s module, %s cable%s%s\n", port_name(port), pm, dte, cable, dsr, dcd); - hdlc_set_carrier(value & STATUS_CABLE_DCD, &port->hdlc); + hdlc_set_carrier(value & STATUS_CABLE_DCD, port_to_dev(port)); } @@ -180,6 +175,8 @@ /* Transmit complete interrupt service */ static inline void wanxl_tx_intr(port_t *port) { + struct net_device *dev = port_to_dev(port); + struct net_device_stats *stats = hdlc_stats(dev); while (1) { desc_t *desc = &get_status(port)->tx_descs[port->tx_in]; struct sk_buff *skb = port->tx_skbs[port->tx_in]; @@ -187,17 +184,17 @@ switch (desc->stat) { case PACKET_FULL: case PACKET_EMPTY: - netif_wake_queue(port_to_dev(port)); + netif_wake_queue(dev); return; case PACKET_UNDERRUN: - port->hdlc.stats.tx_errors++; - port->hdlc.stats.tx_fifo_errors++; + stats->tx_errors++; + stats->tx_fifo_errors++; break; default: - port->hdlc.stats.tx_packets++; - port->hdlc.stats.tx_bytes += skb->len; + stats->tx_packets++; + stats->tx_bytes += skb->len; } desc->stat = PACKET_EMPTY; /* Free descriptor */ pci_unmap_single(port->card->pdev, desc->address, skb->len, @@ -218,13 +215,14 @@ struct sk_buff *skb = card->rx_skbs[card->rx_in]; port_t *port = card->ports[desc->stat & PACKET_PORT_MASK]; struct net_device *dev = port_to_dev(port); + struct net_device_stats *stats = hdlc_stats(dev); if ((desc->stat & PACKET_PORT_MASK) > card->n_ports) printk(KERN_CRIT "wanXL %s: received packet for" " nonexistent port\n", card_name(card->pdev)); else if (!skb) - port->hdlc.stats.rx_dropped++; + stats->rx_dropped++; else { pci_unmap_single(card->pdev, desc->address, @@ -236,8 +234,8 @@ skb->len); debug_frame(skb); #endif - port->hdlc.stats.rx_packets++; - port->hdlc.stats.rx_bytes += skb->len; + stats->rx_packets++; + stats->rx_bytes += skb->len; skb->mac.raw = skb->data; skb->dev = dev; dev->last_rx = jiffies; @@ -290,8 +288,7 @@ static int wanxl_xmit(struct sk_buff *skb, struct net_device *dev) { - hdlc_device *hdlc = dev_to_hdlc(dev); - port_t *port = hdlc_to_port(hdlc); + port_t *port = dev_to_port(dev); desc_t *desc; spin_lock(&port->lock); @@ -338,10 +335,10 @@ -static int wanxl_attach(hdlc_device *hdlc, unsigned short encoding, +static int wanxl_attach(struct net_device *dev, unsigned short encoding, unsigned short parity) { - port_t *port = hdlc_to_port(hdlc); + port_t *port = dev_to_port(dev); if (encoding != ENCODING_NRZ && encoding != ENCODING_NRZI) @@ -365,8 +362,7 @@ { const size_t size = sizeof(sync_serial_settings); sync_serial_settings line; - hdlc_device *hdlc = dev_to_hdlc(dev); - port_t *port = hdlc_to_port(hdlc); + port_t *port = dev_to_port(dev); if (cmd != SIOCWANDEV) return hdlc_ioctl(dev, ifr, cmd); @@ -415,8 +411,7 @@ static int wanxl_open(struct net_device *dev) { - hdlc_device *hdlc = dev_to_hdlc(dev); - port_t *port = hdlc_to_port(hdlc); + port_t *port = dev_to_port(dev); u8 *dbr = port->card->plx + PLX_DOORBELL_TO_CARD; unsigned long timeout; int i; @@ -425,7 +420,7 @@ printk(KERN_ERR "%s: port already open\n", port_name(port)); return -EIO; } - if ((i = hdlc_open(hdlc)) != 0) + if ((i = hdlc_open(dev)) != 0) return i; port->tx_in = port->tx_out = 0; @@ -450,12 +445,11 @@ static int wanxl_close(struct net_device *dev) { - hdlc_device *hdlc = dev_to_hdlc(dev); - port_t *port = hdlc_to_port(hdlc); + port_t *port = dev_to_port(dev); unsigned long timeout; int i; - hdlc_close(hdlc); + hdlc_close(dev); /* signal the card */ writel(1 << (DOORBELL_TO_CARD_CLOSE_0 + port->node), port->card->plx + PLX_DOORBELL_TO_CARD); @@ -487,14 +481,13 @@ static struct net_device_stats *wanxl_get_stats(struct net_device *dev) { - hdlc_device *hdlc = dev_to_hdlc(dev); - port_t *port = hdlc_to_port(hdlc); + struct net_device_stats *stats = hdlc_stats(dev); + port_t *port = dev_to_port(dev); - hdlc->stats.rx_over_errors = get_status(port)->rx_overruns; - hdlc->stats.rx_frame_errors = get_status(port)->rx_frame_errors; - hdlc->stats.rx_errors = hdlc->stats.rx_over_errors + - hdlc->stats.rx_frame_errors; - return &hdlc->stats; + stats->rx_over_errors = get_status(port)->rx_overruns; + stats->rx_frame_errors = get_status(port)->rx_frame_errors; + stats->rx_errors = stats->rx_over_errors + stats->rx_frame_errors; + return stats; } @@ -535,14 +528,16 @@ card_t *card = pci_get_drvdata(pdev); int i; + for (i = 0; i < 4; i++) + if (card->ports[i]) { + struct net_device *dev = port_to_dev(card->ports[i]); + unregister_hdlc_device(dev); + } + /* unregister and free all host resources */ if (card->irq) free_irq(card->irq, card); - for (i = 0; i < 4; i++) - if (card->ports[i]) - unregister_hdlc_device(&card->ports[i]->hdlc); - wanxl_reset(card); for (i = 0; i < RX_QUEUE_LENGTH; i++) @@ -560,6 +555,10 @@ pci_free_consistent(pdev, sizeof(card_status_t), card->status, card->status_address); + for (i = 0; i < card->n_ports; i++) + if (card->__ports[i].dev) + free_netdev(card->__ports[i].dev); + pci_set_drvdata(pdev, NULL); kfree(card); pci_release_regions(pdev); @@ -628,6 +627,16 @@ card->pdev = pdev; card->n_ports = ports; + for (i = 0; i < ports; i++) { + card->__ports[i].dev = alloc_hdlcdev(&card->__ports[i]); + if (!card->__ports[i].dev) { + printk(KERN_ERR "wanXL %s: unable to allocate memory\n", + card_name(pdev)); + wanxl_pci_remove_one(pdev); + return -ENOMEM; + } + } + card->status = pci_alloc_consistent(pdev, sizeof(card_status_t), &card->status_address); if (card->status == NULL) { @@ -708,31 +717,6 @@ return -ENODEV; } - for (i = 0; i < ports; i++) { - port_t *port = (void *)card + sizeof(card_t) + - i * sizeof(port_t); - struct net_device *dev = hdlc_to_dev(&port->hdlc); - spin_lock_init(&port->lock); - SET_MODULE_OWNER(dev); - dev->tx_queue_len = 50; - dev->do_ioctl = wanxl_ioctl; - dev->open = wanxl_open; - dev->stop = wanxl_close; - port->hdlc.attach = wanxl_attach; - port->hdlc.xmit = wanxl_xmit; - if(register_hdlc_device(&port->hdlc)) { - printk(KERN_ERR "wanXL %s: unable to register hdlc" - " device\n", card_name(pdev)); - wanxl_pci_remove_one(pdev); - return -ENOBUFS; - } - card->ports[i] = port; - dev->get_stats = wanxl_get_stats; - port->card = card; - port->node = i; - get_status(port)->clocking = CLOCK_EXT; - } - for (i = 0; i < RX_QUEUE_LENGTH; i++) { struct sk_buff *skb = dev_alloc_skb(BUFFER_LENGTH); card->rx_skbs[i] = skb; @@ -800,6 +784,32 @@ return -EBUSY; } card->irq = pdev->irq; + + for (i = 0; i < ports; i++) { + port_t *port = &card->__ports[i]; + struct net_device *dev = port_to_dev(port); + hdlc_device *hdlc = dev_to_hdlc(dev); + spin_lock_init(&port->lock); + SET_MODULE_OWNER(dev); + dev->tx_queue_len = 50; + dev->do_ioctl = wanxl_ioctl; + dev->open = wanxl_open; + dev->stop = wanxl_close; + hdlc->attach = wanxl_attach; + hdlc->xmit = wanxl_xmit; + card->ports[i] = port; + dev->get_stats = wanxl_get_stats; + port->card = card; + port->node = i; + get_status(port)->clocking = CLOCK_EXT; + if (register_hdlc_device(dev)) { + printk(KERN_ERR "wanXL %s: unable to register hdlc" + " device\n", card_name(pdev)); + card->ports[i] = NULL; + wanxl_pci_remove_one(pdev); + return -ENOBUFS; + } + } return 0; } diff -Nru a/drivers/net/wan/x25_asy.c b/drivers/net/wan/x25_asy.c --- a/drivers/net/wan/x25_asy.c Thu Jan 22 18:59:24 2004 +++ b/drivers/net/wan/x25_asy.c Thu Jan 22 18:59:24 2004 @@ -94,7 +94,7 @@ return sl; } else { printk("x25_asy_alloc() - register_netdev() failure.\n"); - kfree(dev); + free_netdev(dev); } } return NULL; @@ -213,7 +213,7 @@ memcpy(skb_put(skb,count), sl->rbuff, count); skb->mac.raw=skb->data; skb->protocol=htons(ETH_P_X25); - if((err=lapb_data_received(sl,skb))!=LAPB_OK) + if((err=lapb_data_received(skb->dev, skb))!=LAPB_OK) { kfree_skb(skb); printk(KERN_DEBUG "x25_asy: data received err - %d\n",err); @@ -324,12 +324,12 @@ { case 0x00:break; case 0x01: /* Connection request .. do nothing */ - if((err=lapb_connect_request(sl))!=LAPB_OK) + if((err=lapb_connect_request(dev))!=LAPB_OK) printk(KERN_ERR "x25_asy: lapb_connect_request error - %d\n", err); kfree_skb(skb); return 0; case 0x02: /* Disconnect request .. do nothing - hang up ?? */ - if((err=lapb_disconnect_request(sl))!=LAPB_OK) + if((err=lapb_disconnect_request(dev))!=LAPB_OK) printk(KERN_ERR "x25_asy: lapb_disconnect_request error - %d\n", err); default: kfree_skb(skb); @@ -347,7 +347,7 @@ * 14 Oct 1994 Dmitry Gorodchanin. */ - if((err=lapb_data_request(sl,skb))!=LAPB_OK) + if((err=lapb_data_request(dev,skb))!=LAPB_OK) { printk(KERN_ERR "lapbeth: lapb_data_request error - %d\n", err); kfree_skb(skb); @@ -366,7 +366,7 @@ * at the net layer. */ -static int x25_asy_data_indication(void *token, struct sk_buff *skb) +static int x25_asy_data_indication(struct net_device *dev, struct sk_buff *skb) { skb->dev->last_rx = jiffies; return netif_rx(skb); @@ -378,9 +378,9 @@ * perhaps lapb should allow us to bounce this ? */ -static void x25_asy_data_transmit(void *token, struct sk_buff *skb) +static void x25_asy_data_transmit(struct net_device *dev, struct sk_buff *skb) { - struct x25_asy *sl=token; + struct x25_asy *sl=dev->priv; spin_lock(&sl->lock); if (netif_queue_stopped(sl->dev) || sl->tty == NULL) @@ -405,9 +405,9 @@ * LAPB connection establish/down information. */ -static void x25_asy_connected(void *token, int reason) +static void x25_asy_connected(struct net_device *dev, int reason) { - struct x25_asy *sl = token; + struct x25_asy *sl = dev->priv; struct sk_buff *skb; unsigned char *ptr; @@ -428,9 +428,9 @@ sl->dev->last_rx = jiffies; } -static void x25_asy_disconnected(void *token, int reason) +static void x25_asy_disconnected(struct net_device *dev, int reason) { - struct x25_asy *sl = token; + struct x25_asy *sl = dev->priv; struct sk_buff *skb; unsigned char *ptr; @@ -500,7 +500,7 @@ /* * Now attach LAPB */ - if((err=lapb_register(sl, &x25_asy_callbacks))==LAPB_OK) + if((err=lapb_register(dev, &x25_asy_callbacks))==LAPB_OK) return 0; /* Cleanup */ @@ -525,7 +525,7 @@ netif_stop_queue(dev); sl->rcount = 0; sl->xleft = 0; - if((err=lapb_unregister(sl))!=LAPB_OK) + if((err=lapb_unregister(dev))!=LAPB_OK) printk(KERN_ERR "x25_asy_close: lapb_unregister error -%d\n",err); spin_unlock(&sl->lock); return 0; diff -Nru a/drivers/net/wd.c b/drivers/net/wd.c --- a/drivers/net/wd.c Thu Jan 22 18:59:23 2004 +++ b/drivers/net/wd.c Thu Jan 22 18:59:23 2004 @@ -47,7 +47,6 @@ static unsigned int wd_portlist[] __initdata = {0x300, 0x280, 0x380, 0x240, 0}; -int wd_probe(struct net_device *dev); static int wd_probe1(struct net_device *dev, int ioaddr); static int wd_open(struct net_device *dev); @@ -83,11 +82,14 @@ The wd_probe1() routine initializes the card and fills the station address field. */ -int __init wd_probe(struct net_device *dev) +static int __init do_wd_probe(struct net_device *dev) { int i; struct resource *r; int base_addr = dev->base_addr; + int irq = dev->irq; + int mem_start = dev->mem_start; + int mem_end = dev->mem_end; SET_MODULE_OWNER(dev); @@ -115,11 +117,45 @@ return 0; } release_region(ioaddr, WD_IO_EXTENT); + dev->irq = irq; + dev->mem_start = mem_start; + dev->mem_end = mem_end; } return -ENODEV; } +static void cleanup_card(struct net_device *dev) +{ + free_irq(dev->irq, dev); + release_region(dev->base_addr - WD_NIC_OFFSET, WD_IO_EXTENT); +} + +struct net_device * __init wd_probe(int unit) +{ + struct net_device *dev = alloc_ei_netdev(); + int err; + + if (!dev) + return ERR_PTR(-ENOMEM); + + sprintf(dev->name, "eth%d", unit); + netdev_boot_setup_check(dev); + + err = do_wd_probe(dev); + if (err) + goto out; + err = register_netdev(dev); + if (err) + goto out1; + return dev; +out1: + cleanup_card(dev); +out: + free_netdev(dev); + return ERR_PTR(err); +} + static int __init wd_probe1(struct net_device *dev, int ioaddr) { int i; @@ -262,19 +298,11 @@ } else if (dev->irq == 2) /* Fixup bogosity: IRQ2 is really IRQ9 */ dev->irq = 9; - /* Allocate dev->priv and fill in 8390 specific dev fields. */ - if (ethdev_init(dev)) { - printk (" unable to get memory for dev->priv.\n"); - return -ENOMEM; - } - /* Snarf the interrupt now. There's no point in waiting since we cannot share and the board will usually be enabled. */ i = request_irq(dev->irq, ei_interrupt, 0, dev->name, dev); if (i) { printk (" unable to get IRQ %d.\n", dev->irq); - kfree(dev->priv); - dev->priv = NULL; return i; } @@ -305,6 +333,9 @@ ei_status.get_8390_hdr = &wd_get_8390_hdr; dev->open = &wd_open; dev->stop = &wd_close; +#ifdef CONFIG_NET_POLL_CONTROLLER + dev->poll_controller = ei_poll; +#endif NS8390_init(dev, 0); #if 1 @@ -446,7 +477,7 @@ #ifdef MODULE #define MAX_WD_CARDS 4 /* Max number of wd cards per module */ -static struct net_device dev_wd[MAX_WD_CARDS]; +static struct net_device *dev_wd[MAX_WD_CARDS]; static int io[MAX_WD_CARDS]; static int irq[MAX_WD_CARDS]; static int mem[MAX_WD_CARDS]; @@ -468,29 +499,35 @@ int init_module(void) { + struct net_device *dev; int this_dev, found = 0; for (this_dev = 0; this_dev < MAX_WD_CARDS; this_dev++) { - struct net_device *dev = &dev_wd[this_dev]; - dev->irq = irq[this_dev]; - dev->base_addr = io[this_dev]; - dev->mem_start = mem[this_dev]; - dev->mem_end = mem_end[this_dev]; - dev->init = wd_probe; if (io[this_dev] == 0) { if (this_dev != 0) break; /* only autoprobe 1st one */ printk(KERN_NOTICE "wd.c: Presently autoprobing (not recommended) for a single card.\n"); } - if (register_netdev(dev) != 0) { - printk(KERN_WARNING "wd.c: No wd80x3 card found (i/o = 0x%x).\n", io[this_dev]); - if (found != 0) { /* Got at least one. */ - return 0; + dev = alloc_ei_netdev(); + if (!dev) + break; + dev->irq = irq[this_dev]; + dev->base_addr = io[this_dev]; + dev->mem_start = mem[this_dev]; + dev->mem_end = mem_end[this_dev]; + if (do_wd_probe(dev) == 0) { + if (register_netdev(dev) == 0) { + dev_wd[found++] = dev; + continue; } - return -ENXIO; + cleanup_card(dev); } - found++; + free_netdev(dev); + printk(KERN_WARNING "wd.c: No wd80x3 card found (i/o = 0x%x).\n", io[this_dev]); + break; } - return 0; + if (found) + return 0; + return -ENXIO; } void @@ -499,14 +536,11 @@ int this_dev; for (this_dev = 0; this_dev < MAX_WD_CARDS; this_dev++) { - struct net_device *dev = &dev_wd[this_dev]; - if (dev->priv != NULL) { - void *priv = dev->priv; - int ioaddr = dev->base_addr - WD_NIC_OFFSET; - free_irq(dev->irq, dev); - release_region(ioaddr, WD_IO_EXTENT); + struct net_device *dev = dev_wd[this_dev]; + if (dev) { unregister_netdev(dev); - kfree(priv); + cleanup_card(dev); + free_netdev(dev); } } } diff -Nru a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c --- a/drivers/net/wireless/airo.c Thu Jan 22 18:59:23 2004 +++ b/drivers/net/wireless/airo.c Thu Jan 22 18:59:23 2004 @@ -2104,10 +2104,8 @@ return ETH_ALEN; } -static void wifi_setup(struct net_device *dev, struct net_device *ethdev) +static void wifi_setup(struct net_device *dev) { - struct airo_info *ai = ethdev->priv; - dev->priv = ai; dev->hard_header = 0; dev->rebuild_header = 0; dev->hard_header_cache = 0; @@ -2127,14 +2125,11 @@ dev->change_mtu = &airo_change_mtu; dev->open = &airo_open; dev->stop = &airo_close; - dev->irq = ethdev->irq; - dev->base_addr = ethdev->base_addr; dev->type = ARPHRD_IEEE80211; dev->hard_header_len = ETH_HLEN; dev->mtu = 2312; dev->addr_len = ETH_ALEN; - memcpy(dev->dev_addr, ethdev->dev_addr, dev->addr_len); dev->tx_queue_len = 100; memset(dev->broadcast,0xFF, ETH_ALEN); @@ -2146,17 +2141,17 @@ struct net_device *ethdev) { int err; - struct net_device *dev = (struct net_device*)kmalloc(sizeof *dev,GFP_KERNEL); - if (!dev) return 0; - memset(dev, 0, sizeof(*dev)); - - strcpy(dev->name, "wifi%d"); - dev->priv = ai; - wifi_setup(dev, ethdev); + struct net_device *dev = alloc_netdev(0, "wifi%d", wifi_setup); + if (!dev) + return NULL; + dev->priv = ethdev->priv; + dev->irq = ethdev->irq; + dev->base_addr = ethdev->base_addr; + memcpy(dev->dev_addr, ethdev->dev_addr, dev->addr_len); err = register_netdev(dev); if (err<0) { - kfree(dev); - return 0; + free_netdev(dev); + return NULL; } return dev; } @@ -2272,7 +2267,7 @@ kill_proc(ai->thr_pid, SIGTERM, 1); wait_for_completion(&ai->thr_exited); err_out_free: - kfree(dev); + free_netdev(dev); return NULL; } diff -Nru a/drivers/net/wireless/airport.c b/drivers/net/wireless/airport.c --- a/drivers/net/wireless/airport.c Thu Jan 22 18:59:26 2004 +++ b/drivers/net/wireless/airport.c Thu Jan 22 18:59:26 2004 @@ -216,7 +216,7 @@ if (! request_OF_resource(of_node, 0, " (airport)")) { printk(KERN_ERR "airport: can't request IO resource !\n"); - kfree(dev); + free_netdev(dev); return -ENODEV; } diff -Nru a/drivers/net/wireless/arlan-main.c b/drivers/net/wireless/arlan-main.c --- a/drivers/net/wireless/arlan-main.c Thu Jan 22 18:59:25 2004 +++ b/drivers/net/wireless/arlan-main.c Thu Jan 22 18:59:25 2004 @@ -19,9 +19,7 @@ static int SID = SIDUNKNOWN; static int radioNodeId = radioNodeIdUNKNOWN; static char encryptionKey[12] = {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'}; -static int mem = memUNKNOWN; int arlan_debug = debugUNKNOWN; -static int numDevices = numDevicesUNKNOWN; static int spreadingCode = spreadingCodeUNKNOWN; static int channelNumber = channelNumberUNKNOWN; static int channelSet = channelSetUNKNOWN; @@ -45,9 +43,7 @@ MODULE_PARM(irq, "i"); MODULE_PARM(mem, "i"); -MODULE_PARM(probe, "i"); MODULE_PARM(arlan_debug, "i"); -MODULE_PARM(numDevices, "i"); MODULE_PARM(testMemory, "i"); MODULE_PARM(spreadingCode, "i"); MODULE_PARM(channelNumber, "i"); @@ -69,9 +65,7 @@ MODULE_PARM(arlan_EEPROM_bad, "i"); MODULE_PARM_DESC(irq, "(unused)"); MODULE_PARM_DESC(mem, "Arlan memory address for single device probing"); -MODULE_PARM_DESC(probe, "Arlan probe at initialization (0-1)"); MODULE_PARM_DESC(arlan_debug, "Arlan debug enable (0-1)"); -MODULE_PARM_DESC(numDevices, "Number of Arlan devices; ignored if >1"); MODULE_PARM_DESC(testMemory, "(unused)"); MODULE_PARM_DESC(mdebug, "Arlan multicast debugging (0-1)"); MODULE_PARM_DESC(retries, "Arlan maximum packet retransmisions"); @@ -88,7 +82,6 @@ struct arlan_conf_stru arlan_conf[MAX_ARLANS]; static int arlans_found; -static int arlan_probe_here(struct net_device *dev, int ioaddr); static int arlan_open(struct net_device *dev); static int arlan_tx(struct sk_buff *skb, struct net_device *dev); static irqreturn_t arlan_interrupt(int irq, void *dev_id, struct pt_regs *regs); @@ -975,24 +968,27 @@ * probes on the ISA bus. A good device probes avoids doing writes, and * verifies that the correct device exists and functions. */ - -static int __init arlan_check_fingerprint(int memaddr) +#define ARLAN_SHMEM_SIZE 0x2000 +static int __init arlan_check_fingerprint(unsigned long memaddr) { - static char probeText[] = "TELESYSTEM SLW INC. ARLAN \0"; - char tempBuf[49]; + static const char probeText[] = "TELESYSTEM SLW INC. ARLAN \0"; volatile struct arlan_shmem *arlan = (struct arlan_shmem *) memaddr; + unsigned long paddr = virt_to_phys((void *) memaddr); + char tempBuf[49]; ARLAN_DEBUG_ENTRY("arlan_check_fingerprint"); - if (check_mem_region(virt_to_phys((void *)memaddr),0x2000 )){ - // printk(KERN_WARNING "arlan: memory region %lx excluded from probing \n",virt_to_phys((void*)memaddr)); + + if (!request_mem_region(paddr, ARLAN_SHMEM_SIZE, "arlan")) { + // printk(KERN_WARNING "arlan: memory region %lx excluded from probing \n",paddr); return -ENODEV; } + memcpy_fromio(tempBuf, arlan->textRegion, 29); tempBuf[30] = 0; /* check for card at this address */ if (0 != strncmp(tempBuf, probeText, 29)){ -// not release_mem_region(virt_to_phys((void*)memaddr),0x2000); + release_mem_region(paddr, ARLAN_SHMEM_SIZE); return -ENODEV; } @@ -1000,51 +996,8 @@ ARLAN_DEBUG_EXIT("arlan_check_fingerprint"); return 0; - - -} - -static int __init arlan_probe_everywhere(struct net_device *dev) -{ - int m; - int probed = 0; - int found = 0; - - SET_MODULE_OWNER(dev); - - ARLAN_DEBUG_ENTRY("arlan_probe_everywhere"); - if (mem != 0 && numDevices == 1) /* Check a single specified location. */ - { - if (arlan_probe_here(dev, (int) phys_to_virt( mem) ) == 0) - return 0; - else - return -ENODEV; - } - for (m = (int)phys_to_virt(lastFoundAt) + 0x2000; m <= (int)phys_to_virt(0xDE000); m += 0x2000) - { - if (arlan_probe_here(dev, m) == 0) - { - found++; - lastFoundAt = (int)virt_to_phys((void*)m); - break; - } - probed++; - } - if (found == 0 && probed != 0) - { - if (lastFoundAt == 0xbe000) - printk(KERN_ERR "arlan: No Arlan devices found \n"); - return -ENODEV; - } - else - return 0; - - ARLAN_DEBUG_EXIT("arlan_probe_everywhere"); - - return -ENODEV; } - static int arlan_change_mtu(struct net_device *dev, int new_mtu) { struct arlan_private *priv = dev->priv; @@ -1085,47 +1038,15 @@ - -static int __init - arlan_allocate_device(int num, struct net_device *devs) +static int __init arlan_setup_device(struct net_device *dev, int num) { + struct arlan_private *ap = dev->priv; + int err; - struct net_device *dev; - struct arlan_private *ap; + ARLAN_DEBUG_ENTRY("arlan_setup_device"); - ARLAN_DEBUG_ENTRY("arlan_allocate_device"); + ap->conf = (struct arlan_shmem *)(ap+1); - if (!devs) { - dev = init_etherdev(0, sizeof(struct arlan_private) + sizeof(struct arlan_shmem)); - if (!dev) { - printk(KERN_ERR "ARLAN: init_etherdev failed\n"); - return 0; - } - ap = dev->priv; - ap->conf = dev->priv + sizeof(struct arlan_private); - ap->init_etherdev_alloc = 1; - } else { - dev = devs; - dev->priv = kmalloc(sizeof(struct arlan_private) + sizeof(struct arlan_shmem), GFP_KERNEL); - if (!dev->priv) { - printk(KERN_ERR "ARLAN: kmalloc of dev->priv failed\n"); - return 0; - } - ap = dev->priv; - ap->conf = dev->priv + sizeof(struct arlan_private); - memset(ap, 0, sizeof(*ap)); - } - - /* Fill in the 'dev' fields. */ - dev->base_addr = 0; - dev->mem_start = 0; - dev->mem_end = 0; - dev->mtu = 1500; - dev->flags = 0; /* IFF_BROADCAST & IFF_MULTICAST & IFF_PROMISC; */ - dev->irq = 0; - dev->dma = 0; - dev->tx_queue_len = tx_queue_len; - ether_setup(dev); dev->tx_queue_len = tx_queue_len; dev->open = arlan_open; dev->stop = arlan_close; @@ -1138,41 +1059,45 @@ dev->watchdog_timeo = 3*HZ; ap->irq_test_done = 0; - arlan_device[num] = dev; ap->Conf = &arlan_conf[num]; ap->Conf->pre_Command_Wait = 40; ap->Conf->rx_tweak1 = 30; ap->Conf->rx_tweak2 = 0; - ARLAN_DEBUG_EXIT("arlan_allocate_device"); - return (int) dev; -} + err = register_netdev(dev); + if (err) { + release_mem_region(virt_to_phys((void *) dev->mem_start), + ARLAN_SHMEM_SIZE); + free_netdev(dev); + return err; + } + arlan_device[num] = dev; + ARLAN_DEBUG_EXIT("arlan_setup_device"); + return 0; +} -static int __init arlan_probe_here(struct net_device *dev, int memaddr) +static int __init arlan_probe_here(struct net_device *dev, + unsigned long memaddr) { - volatile struct arlan_shmem *arlan; + struct arlan_private *ap = dev->priv; ARLAN_DEBUG_ENTRY("arlan_probe_here"); if (arlan_check_fingerprint(memaddr)) return -ENODEV; - printk(KERN_NOTICE "%s: Arlan found at %x, \n ", dev->name, (int) virt_to_phys((void*)memaddr)); - - if (!arlan_allocate_device(arlans_found, dev)) - return -1; - - ((struct arlan_private *) dev->priv)->card = (struct arlan_shmem *) memaddr; - arlan = (void *) memaddr; + printk(KERN_NOTICE "%s: Arlan found at %x, \n ", dev->name, + (int) virt_to_phys((void*)memaddr)); + ap->card = (void *) memaddr; dev->mem_start = memaddr; - dev->mem_end = memaddr + 0x1FFF; + dev->mem_end = memaddr + ARLAN_SHMEM_SIZE-1; if (dev->irq < 2) { - READSHM(dev->irq, arlan->irqLevel, u_char); + READSHM(dev->irq, ap->card->irqLevel, u_char); } else if (dev->irq == 2) dev->irq = 9; @@ -1183,8 +1108,6 @@ } - - static int arlan_open(struct net_device *dev) { struct arlan_private *priv = dev->priv; @@ -1193,12 +1116,6 @@ ARLAN_DEBUG_ENTRY("arlan_open"); - if (dev->mem_start == 0) - ret = arlan_probe_everywhere(dev); - if (ret != 0) - return ret; - - arlan = priv->card; ret = request_irq(dev->irq, &arlan_interrupt, 0, dev->name, dev); if (ret) { @@ -1768,14 +1685,9 @@ { struct arlan_private *priv = dev->priv; - if (!priv) - { - printk(KERN_CRIT "arlan: No Device priv \n"); - return 0; - } ARLAN_DEBUG_ENTRY("arlan_close"); - del_timer(&priv->timer); + del_timer_sync(&priv->timer); arlan_command(dev, ARLAN_COMMAND_POWERDOWN); @@ -1867,39 +1779,70 @@ } -int __init arlan_probe(struct net_device *dev) +struct net_device * __init arlan_probe(int unit) { - printk("Arlan driver %s\n", arlan_version); + struct net_device *dev; + int err; + int m; - if (arlan_probe_everywhere(dev)) - return -ENODEV; + ARLAN_DEBUG_ENTRY("arlan_probe"); - arlans_found++; - return 0; -} + if (arlans_found == MAX_ARLANS) + return ERR_PTR(-ENODEV); -#ifdef MODULE + /* + * Reserve space for local data and a copy of the shared memory + * that is used by the /proc interface. + */ + dev = alloc_etherdev(sizeof(struct arlan_private) + + sizeof(struct arlan_shmem)); + if (!dev) + return ERR_PTR(-ENOMEM); -static int probe = probeUNKNOWN; + SET_MODULE_OWNER(dev); -static int __init arlan_find_devices(void) -{ - int m; - int found = 0; + if (unit >= 0) { + sprintf(dev->name, "eth%d", unit); + netdev_boot_setup_check(dev); + + if (dev->mem_start) { + if (arlan_probe_here(dev, dev->mem_start) == 0) + goto found; + goto not_found; + } + + } - ARLAN_DEBUG_ENTRY("arlan_find_devices"); - if (mem != 0 && numDevices == 1) /* Check a single specified location. */ - return 1; - for (m =(int) phys_to_virt(0xc0000); m <=(int) phys_to_virt(0xDE000); m += 0x2000) + + for (m = (int)phys_to_virt(lastFoundAt) + ARLAN_SHMEM_SIZE; + m <= (int)phys_to_virt(0xDE000); + m += ARLAN_SHMEM_SIZE) { - if (arlan_check_fingerprint(m) == 0) - found++; + if (arlan_probe_here(dev, m) == 0) + { + lastFoundAt = (int)virt_to_phys((void*)m); + goto found; + } } - ARLAN_DEBUG_EXIT("arlan_find_devices"); - return found; + if (lastFoundAt == 0xbe000) + printk(KERN_ERR "arlan: No Arlan devices found \n"); + + not_found: + free_netdev(dev); + return ERR_PTR(-ENODEV); + + found: + err = arlan_setup_device(dev, arlans_found); + if (err) + dev = ERR_PTR(err); + else if (!arlans_found++) + printk(KERN_INFO "Arlan driver %s\n", arlan_version); + + return dev; } +#ifdef MODULE int init_module(void) { int i = 0; @@ -1909,21 +1852,11 @@ if (channelSet != channelSetUNKNOWN || channelNumber != channelNumberUNKNOWN || systemId != systemIdUNKNOWN) return -EINVAL; - numDevices = arlan_find_devices(); - if (numDevices == 0) - return -ENODEV; - - for (i = 0; i < numDevices && i < MAX_ARLANS; i++) - { - if (!arlan_allocate_device(i, NULL)) - return -ENOMEM; + for (i = 0; i < MAX_ARLANS; i++) { + struct net_device *dev = arlan_probe(i); - if (arlan_device[i] == NULL) - return -ENOMEM; - - if (probe) - arlan_probe_everywhere(arlan_device[i]); -// arlan_command(arlan_device[i], ARLAN_COMMAND_POWERDOWN ); + if (IS_ERR(dev)) + return PTR_ERR(dev); } init_arlan_proc(); printk(KERN_INFO "Arlan driver %s\n", arlan_version); @@ -1935,7 +1868,7 @@ void cleanup_module(void) { int i = 0; - struct arlan_private *ap; + struct net_device *dev; ARLAN_DEBUG_ENTRY("cleanup_module"); @@ -1946,22 +1879,18 @@ for (i = 0; i < MAX_ARLANS; i++) { - if (arlan_device[i]) - { - arlan_command(arlan_device[i], ARLAN_COMMAND_POWERDOWN ); - -// release_mem_region(virt_to_phys(arlan_device[i]->mem_start), 0x2000 ); - unregister_netdev(arlan_device[i]); - ap = arlan_device[i]->priv; - if (ap->init_etherdev_alloc) { - free_netdev(arlan_device[i]); - arlan_device[i] = NULL; - } else { - kfree(ap); - ap = NULL; - } + dev = arlan_device[i]; + if (dev) { + arlan_command(dev, ARLAN_COMMAND_POWERDOWN ); + + unregister_netdev(dev); + release_mem_region(virt_to_phys((void *) dev->mem_start), + ARLAN_SHMEM_SIZE); + free_netdev(dev); + arlan_device[i] = NULL; } } + ARLAN_DEBUG_EXIT("cleanup_module"); } diff -Nru a/drivers/net/wireless/arlan.h b/drivers/net/wireless/arlan.h --- a/drivers/net/wireless/arlan.h Thu Jan 22 18:59:25 2004 +++ b/drivers/net/wireless/arlan.h Thu Jan 22 18:59:25 2004 @@ -57,12 +57,8 @@ #define SIDUNKNOWN -1 #define radioNodeIdUNKNOWN -1 -#define encryptionKeyUNKNOWN '\0'; #define irqUNKNOWN 0 -#define memUNKNOWN 0 #define debugUNKNOWN 0 -#define probeUNKNOWN 1 -#define numDevicesUNKNOWN 1 #define testMemoryUNKNOWN 1 #define spreadingCodeUNKNOWN 0 #define channelNumberUNKNOWN 0 @@ -81,6 +77,8 @@ #else #define ARLAN_DEBUG(a,b) #endif + +#define ARLAN_SHMEM_SIZE 0x2000 struct arlan_shmem { diff -Nru a/drivers/net/wireless/orinoco.c b/drivers/net/wireless/orinoco.c --- a/drivers/net/wireless/orinoco.c Thu Jan 22 18:59:27 2004 +++ b/drivers/net/wireless/orinoco.c Thu Jan 22 18:59:27 2004 @@ -4129,6 +4129,8 @@ struct orinoco_private *priv; dev = alloc_etherdev(sizeof(struct orinoco_private) + sizeof_card); + if (!dev) + return NULL; priv = (struct orinoco_private *)dev->priv; priv->ndev = dev; if (sizeof_card) diff -Nru a/drivers/net/wireless/orinoco_pci.c b/drivers/net/wireless/orinoco_pci.c --- a/drivers/net/wireless/orinoco_pci.c Thu Jan 22 18:59:26 2004 +++ b/drivers/net/wireless/orinoco_pci.c Thu Jan 22 18:59:26 2004 @@ -261,7 +261,7 @@ if (dev->irq) free_irq(dev->irq, dev); - kfree(dev); + free_netdev(dev); } if (pci_ioaddr) diff -Nru a/drivers/net/wireless/orinoco_plx.c b/drivers/net/wireless/orinoco_plx.c --- a/drivers/net/wireless/orinoco_plx.c Thu Jan 22 18:59:26 2004 +++ b/drivers/net/wireless/orinoco_plx.c Thu Jan 22 18:59:26 2004 @@ -263,7 +263,7 @@ if (dev->irq) free_irq(dev->irq, dev); - kfree(dev); + free_netdev(dev); } if (pccard_ioaddr) diff -Nru a/drivers/net/wireless/orinoco_tmd.c b/drivers/net/wireless/orinoco_tmd.c --- a/drivers/net/wireless/orinoco_tmd.c Thu Jan 22 18:59:24 2004 +++ b/drivers/net/wireless/orinoco_tmd.c Thu Jan 22 18:59:24 2004 @@ -157,7 +157,7 @@ if (dev->irq) free_irq(dev->irq, dev); - kfree(dev); + free_netdev(dev); } if (pccard_ioaddr) diff -Nru a/drivers/net/wireless/ray_cs.c b/drivers/net/wireless/ray_cs.c --- a/drivers/net/wireless/ray_cs.c Thu Jan 22 18:59:24 2004 +++ b/drivers/net/wireless/ray_cs.c Thu Jan 22 18:59:24 2004 @@ -344,19 +344,14 @@ return NULL; /* Allocate space for private device-specific data */ - dev = kmalloc(sizeof(struct net_device), GFP_KERNEL); + dev = alloc_etherdev(sizeof(ray_dev_t)); if (!dev) goto fail_alloc_dev; - local = kmalloc(sizeof(ray_dev_t), GFP_KERNEL); - - if (!local) - goto fail_alloc_local; + local = dev->priv; memset(link, 0, sizeof(struct dev_link_t)); - memset(dev, 0, sizeof(struct net_device)); - memset(local, 0, sizeof(ray_dev_t)); /* The io structure describes IO port mapping. None used here */ link->io.NumPorts1 = 0; @@ -379,7 +374,6 @@ link->priv = dev; link->irq.Instance = dev; - dev->priv = local; local->finder = link; local->card_status = CARD_INSERTED; local->authentication_state = UNAUTHENTICATED; @@ -401,7 +395,6 @@ DEBUG(2,"ray_cs ray_attach calling ether_setup.)\n"); SET_MODULE_OWNER(dev); - ether_setup(dev); dev->init = &ray_dev_init; dev->open = &ray_open; dev->stop = &ray_dev_close; @@ -434,8 +427,6 @@ DEBUG(2,"ray_cs ray_attach ending\n"); return link; -fail_alloc_local: - kfree(dev); fail_alloc_dev: kfree(link); return NULL; @@ -478,9 +469,7 @@ if (link->priv) { struct net_device *dev = link->priv; if (link->dev) unregister_netdev(dev); - if (dev->priv) - kfree(dev->priv); - kfree(link->priv); + free_netdev(dev); } kfree(link); DEBUG(2,"ray_cs ray_detach ending\n"); diff -Nru a/drivers/net/wireless/strip.c b/drivers/net/wireless/strip.c --- a/drivers/net/wireless/strip.c Thu Jan 22 18:59:26 2004 +++ b/drivers/net/wireless/strip.c Thu Jan 22 18:59:26 2004 @@ -2564,7 +2564,7 @@ strip_info->magic = 0; - kfree(strip_info->dev); + free_netdev(strip_info->dev); } diff -Nru a/drivers/net/wireless/wavelan.c b/drivers/net/wireless/wavelan.c --- a/drivers/net/wireless/wavelan.c Thu Jan 22 18:59:26 2004 +++ b/drivers/net/wireless/wavelan.c Thu Jan 22 18:59:26 2004 @@ -153,7 +153,7 @@ * Disable interrupts on the WaveLAN hardware. * (called by wv_82586_stop()) */ -static inline void wv_ints_off(device * dev) +static inline void wv_ints_off(struct net_device * dev) { net_local *lp = (net_local *) dev->priv; unsigned long ioaddr = dev->base_addr; @@ -167,7 +167,7 @@ * Enable interrupts on the WaveLAN hardware. * (called by wv_hw_reset()) */ -static inline void wv_ints_on(device * dev) +static inline void wv_ints_on(struct net_device * dev) { net_local *lp = (net_local *) dev->priv; unsigned long ioaddr = dev->base_addr; @@ -268,7 +268,7 @@ /* * update the checksum field in the Wavelan's PSA */ -static void update_psa_checksum(device * dev, unsigned long ioaddr, u16 hacr) +static void update_psa_checksum(struct net_device * dev, unsigned long ioaddr, u16 hacr) { #ifdef SET_PSA_CRC psa_t psa; @@ -547,7 +547,7 @@ /* * Acknowledge the reading of the status issued by the i82586. */ -static void wv_ack(device * dev) +static void wv_ack(struct net_device * dev) { net_local *lp = (net_local *) dev->priv; unsigned long ioaddr = dev->base_addr; @@ -589,7 +589,7 @@ * Set channel attention bit and busy wait until command has * completed, then acknowledge completion of the command. */ -static inline int wv_synchronous_cmd(device * dev, const char *str) +static inline int wv_synchronous_cmd(struct net_device * dev, const char *str) { net_local *lp = (net_local *) dev->priv; unsigned long ioaddr = dev->base_addr; @@ -636,7 +636,7 @@ * Check if done, and if OK. */ static inline int -wv_config_complete(device * dev, unsigned long ioaddr, net_local * lp) +wv_config_complete(struct net_device * dev, unsigned long ioaddr, net_local * lp) { unsigned short mcs_addr; unsigned short status; @@ -703,7 +703,7 @@ * (called in wavelan_interrupt()). * Note : the spinlock is already grabbed for us. */ -static int wv_complete(device * dev, unsigned long ioaddr, net_local * lp) +static int wv_complete(struct net_device * dev, unsigned long ioaddr, net_local * lp) { int nreaped = 0; @@ -845,7 +845,7 @@ * wavelan_interrupt is not an option), so you may experience * delays sometimes. */ -static inline void wv_82586_reconfig(device * dev) +static inline void wv_82586_reconfig(struct net_device * dev) { net_local *lp = (net_local *) dev->priv; unsigned long flags; @@ -954,7 +954,7 @@ * Print the formatted status of the Modem Management Controller. * This function needs to be completed. */ -static void wv_mmc_show(device * dev) +static void wv_mmc_show(struct net_device * dev) { unsigned long ioaddr = dev->base_addr; net_local *lp = (net_local *) dev->priv; @@ -1137,7 +1137,7 @@ /* * Print the formatted status of the i82586's receive unit. */ -static void wv_ru_show(device * dev) +static void wv_ru_show(struct net_device * dev) { /* net_local *lp = (net_local *) dev->priv; */ @@ -1154,7 +1154,7 @@ /* * Display info about one control block of the i82586 memory. */ -static void wv_cu_show_one(device * dev, net_local * lp, int i, u16 p) +static void wv_cu_show_one(struct net_device * dev, net_local * lp, int i, u16 p) { unsigned long ioaddr; ac_tx_t actx; @@ -1183,7 +1183,7 @@ /* * Print status of the command unit of the i82586. */ -static void wv_cu_show(device * dev) +static void wv_cu_show(struct net_device * dev) { net_local *lp = (net_local *) dev->priv; unsigned int i; @@ -1209,7 +1209,7 @@ /* * Print the formatted status of the WaveLAN PCMCIA device driver. */ -static void wv_dev_show(device * dev) +static void wv_dev_show(struct net_device * dev) { printk(KERN_DEBUG "dev:"); printk(" state=%lX,", dev->state); @@ -1223,7 +1223,7 @@ * Print the formatted status of the WaveLAN PCMCIA device driver's * private information. */ -static void wv_local_show(device * dev) +static void wv_local_show(struct net_device * dev) { net_local *lp; @@ -1285,7 +1285,7 @@ * This is the information which is displayed by the driver at startup. * There are lots of flags for configuring it to your liking. */ -static inline void wv_init_info(device * dev) +static inline void wv_init_info(struct net_device * dev) { short ioaddr = dev->base_addr; net_local *lp = (net_local *) dev->priv; @@ -1395,7 +1395,7 @@ * card open or closed. * Used when the user read /proc/net/dev */ -static en_stats *wavelan_get_stats(device * dev) +static en_stats *wavelan_get_stats(struct net_device * dev) { #ifdef DEBUG_IOCTL_TRACE printk(KERN_DEBUG "%s: <>wavelan_get_stats()\n", dev->name); @@ -1412,7 +1412,7 @@ * num_addrs > 0 Multicast mode, receive normal and MC packets, * and do best-effort filtering. */ -static void wavelan_set_multicast_list(device * dev) +static void wavelan_set_multicast_list(struct net_device * dev) { net_local *lp = (net_local *) dev->priv; @@ -1485,7 +1485,7 @@ * (Note : it was a nice way to test the reconfigure stuff...) */ #ifdef SET_MAC_ADDRESS -static int wavelan_set_mac_address(device * dev, void *addr) +static int wavelan_set_mac_address(struct net_device * dev, void *addr) { struct sockaddr *mac = addr; @@ -1724,7 +1724,7 @@ * address with our list, and if they match, get the statistics. * Sorry, but this function really needs the wireless extensions. */ -static inline void wl_spy_gather(device * dev, +static inline void wl_spy_gather(struct net_device * dev, u8 * mac, /* MAC address */ u8 * stats) /* Statistics to gather */ { @@ -1750,7 +1750,7 @@ * With this histogram you may detect if one WaveLAN is really weak, * or you may also calculate the mean and standard deviation of the level. */ -static inline void wl_his_gather(device * dev, u8 * stats) +static inline void wl_his_gather(struct net_device * dev, u8 * stats) { /* Statistics to gather */ net_local *lp = (net_local *) dev->priv; u8 level = stats[0] & MMR_SIGNAL_LVL; @@ -2415,7 +2415,7 @@ * Get wireless statistics. * Called by /proc/net/wireless */ -static iw_stats *wavelan_get_wireless_stats(device * dev) +static iw_stats *wavelan_get_wireless_stats(struct net_device * dev) { unsigned long ioaddr = dev->base_addr; net_local *lp = (net_local *) dev->priv; @@ -2492,7 +2492,7 @@ * (called by wv_packet_rcv()) */ static inline void -wv_packet_read(device * dev, u16 buf_off, int sksize) +wv_packet_read(struct net_device * dev, u16 buf_off, int sksize) { net_local *lp = (net_local *) dev->priv; unsigned long ioaddr = dev->base_addr; @@ -2587,7 +2587,7 @@ * (called in wavelan_interrupt()). * Note : the spinlock is already grabbed for us. */ -static inline void wv_receive(device * dev) +static inline void wv_receive(struct net_device * dev) { unsigned long ioaddr = dev->base_addr; net_local *lp = (net_local *) dev->priv; @@ -2770,7 +2770,7 @@ * * (called in wavelan_packet_xmit()) */ -static inline int wv_packet_write(device * dev, void *buf, short length) +static inline int wv_packet_write(struct net_device * dev, void *buf, short length) { net_local *lp = (net_local *) dev->priv; unsigned long ioaddr = dev->base_addr; @@ -2901,7 +2901,7 @@ * the packet. We also prevent reentrance. Then we call the function * to send the packet. */ -static int wavelan_packet_xmit(struct sk_buff *skb, device * dev) +static int wavelan_packet_xmit(struct sk_buff *skb, struct net_device * dev) { net_local *lp = (net_local *) dev->priv; unsigned long flags; @@ -2966,7 +2966,7 @@ * Routine to initialize the Modem Management Controller. * (called by wv_hw_reset()) */ -static inline int wv_mmc_init(device * dev) +static inline int wv_mmc_init(struct net_device * dev) { unsigned long ioaddr = dev->base_addr; net_local *lp = (net_local *) dev->priv; @@ -3138,7 +3138,7 @@ * Start the receive unit. * (called by wv_hw_reset()) */ -static inline int wv_ru_start(device * dev) +static inline int wv_ru_start(struct net_device * dev) { net_local *lp = (net_local *) dev->priv; unsigned long ioaddr = dev->base_addr; @@ -3230,7 +3230,7 @@ * * (called by wv_hw_reset()) */ -static inline int wv_cu_start(device * dev) +static inline int wv_cu_start(struct net_device * dev) { net_local *lp = (net_local *) dev->priv; unsigned long ioaddr = dev->base_addr; @@ -3331,7 +3331,7 @@ * * (called by wv_hw_reset()) */ -static inline int wv_82586_start(device * dev) +static inline int wv_82586_start(struct net_device * dev) { net_local *lp = (net_local *) dev->priv; unsigned long ioaddr = dev->base_addr; @@ -3463,7 +3463,7 @@ * * (called by wv_hw_reset(), wv_82586_reconfig(), wavelan_packet_xmit()) */ -static void wv_82586_config(device * dev) +static void wv_82586_config(struct net_device * dev) { net_local *lp = (net_local *) dev->priv; unsigned long ioaddr = dev->base_addr; @@ -3643,7 +3643,7 @@ * WaveLAN controller (i82586). * (called by wavelan_close()) */ -static inline void wv_82586_stop(device * dev) +static inline void wv_82586_stop(struct net_device * dev) { net_local *lp = (net_local *) dev->priv; unsigned long ioaddr = dev->base_addr; @@ -3680,7 +3680,7 @@ * 5. Start the LAN controller's receive unit * (called by wavelan_interrupt(), wavelan_watchdog() & wavelan_open()) */ -static int wv_hw_reset(device * dev) +static int wv_hw_reset(struct net_device * dev) { net_local *lp = (net_local *) dev->priv; unsigned long ioaddr = dev->base_addr; @@ -3770,7 +3770,7 @@ */ static irqreturn_t wavelan_interrupt(int irq, void *dev_id, struct pt_regs *regs) { - device *dev; + struct net_device *dev; unsigned long ioaddr; net_local *lp; u16 hasr; @@ -3923,7 +3923,7 @@ * kernel. If the transmission completes, this timer is disabled. If * the timer expires, we are called and we try to unlock the hardware. */ -static void wavelan_watchdog(device * dev) +static void wavelan_watchdog(struct net_device * dev) { net_local * lp = (net_local *)dev->priv; u_long ioaddr = dev->base_addr; @@ -4003,7 +4003,7 @@ * Configure and start up the WaveLAN PCMCIA adaptor. * Called by NET3 when it "opens" the device. */ -static int wavelan_open(device * dev) +static int wavelan_open(struct net_device * dev) { net_local * lp = (net_local *)dev->priv; unsigned long flags; @@ -4058,7 +4058,7 @@ * Shut down the WaveLAN ISA card. * Called by NET3 when it "closes" the device. */ -static int wavelan_close(device * dev) +static int wavelan_close(struct net_device * dev) { net_local *lp = (net_local *) dev->priv; unsigned long flags; @@ -4091,12 +4091,24 @@ * device structure * (called by wavelan_probe() and via init_module()). */ -static int __init wavelan_config(device * dev) +static int __init wavelan_config(struct net_device *dev, unsigned short ioaddr) { - unsigned long ioaddr = dev->base_addr; u8 irq_mask; int irq; net_local *lp; + mac_addr mac; + int err; + + if (!request_region(ioaddr, sizeof(ha_t), "wavelan")) + return -EADDRINUSE; + + err = wv_check_ioaddr(ioaddr, mac); + if (err) + goto out; + + memcpy(dev->dev_addr, mac, 6); + + dev->base_addr = ioaddr; #ifdef DEBUG_CALLBACK_TRACE printk(KERN_DEBUG "%s: ->wavelan_config(dev=0x%x, ioaddr=0x%lx)\n", @@ -4136,25 +4148,18 @@ "%s: wavelan_config(): could not wavelan_map_irq(%d).\n", dev->name, irq_mask); #endif - return -EAGAIN; + err = -EAGAIN; + goto out; } dev->irq = irq; - if (!request_region(ioaddr, sizeof(ha_t), "wavelan")) - return -EBUSY; - dev->mem_start = 0x0000; dev->mem_end = 0x0000; dev->if_port = 0; /* Initialize device structures */ - dev->priv = kmalloc(sizeof(net_local), GFP_KERNEL); - if (dev->priv == NULL) { - release_region(ioaddr, sizeof(ha_t)); - return -ENOMEM; - } - memset(dev->priv, 0x00, sizeof(net_local)); + memset(dev->priv, 0, sizeof(net_local)); lp = (net_local *) dev->priv; /* Back link to the device structure. */ @@ -4172,12 +4177,6 @@ /* Init spinlock */ spin_lock_init(&lp->spinlock); - /* - * Fill in the fields of the device structure - * with generic Ethernet values. - */ - ether_setup(dev); - SET_MODULE_OWNER(dev); dev->open = wavelan_open; dev->stop = wavelan_close; @@ -4204,6 +4203,9 @@ printk(KERN_DEBUG "%s: <-wavelan_config()\n", dev->name); #endif return 0; +out: + release_region(ioaddr, sizeof(ha_t)); + return err; } /*------------------------------------------------------------------*/ @@ -4214,19 +4216,13 @@ * We follow the example in drivers/net/ne.c. * (called in "Space.c") */ -int __init wavelan_probe(device * dev) +struct net_device * __init wavelan_probe(int unit) { + struct net_device *dev; short base_addr; - mac_addr mac; /* MAC address (check existence of WaveLAN) */ + int def_irq; int i; - int r; - -#ifdef DEBUG_CALLBACK_TRACE - printk(KERN_DEBUG - "%s: ->wavelan_probe(dev=0x%x (base_addr=0x%x))\n", - dev->name, (unsigned int) dev, - (unsigned int) dev->base_addr); -#endif + int r = 0; #ifdef STRUCT_CHECK if (wv_struct_check() != (char *) NULL) { @@ -4237,8 +4233,20 @@ } #endif /* STRUCT_CHECK */ - /* Check the value of the command line parameter for base address. */ + dev = alloc_etherdev(sizeof(net_local)); + if (!dev) + return ERR_PTR(-ENOMEM); + + sprintf(dev->name, "eth%d", unit); + netdev_boot_setup_check(dev); base_addr = dev->base_addr; + def_irq = dev->irq; + +#ifdef DEBUG_CALLBACK_TRACE + printk(KERN_DEBUG + "%s: ->wavelan_probe(dev=%p (base_addr=0x%x))\n", + dev->name, dev, (unsigned int) dev->base_addr); +#endif /* Don't probe at all. */ if (base_addr < 0) { @@ -4247,16 +4255,9 @@ "%s: wavelan_probe(): invalid base address\n", dev->name); #endif - return -ENXIO; - } - - /* Check a single specified location. */ - if (base_addr > 0x100) { - /* Check if there is something at this base address */ - if ((r = wv_check_ioaddr(base_addr, mac)) == 0) { - memcpy(dev->dev_addr, mac, 6); /* Copy MAC address. */ - r = wavelan_config(dev); - } + r = -ENXIO; + } else if (base_addr > 0x100) { /* Check a single specified location. */ + r = wavelan_config(dev, base_addr); #ifdef DEBUG_CONFIG_INFO if (r != 0) printk(KERN_DEBUG @@ -4267,35 +4268,33 @@ #ifdef DEBUG_CALLBACK_TRACE printk(KERN_DEBUG "%s: <-wavelan_probe()\n", dev->name); #endif - return r; - } - - /* Scan all possible addresses of the WaveLAN hardware. */ - for (i = 0; i < NELS(iobase); i++) { - /* Check whether there is something at this base address. */ - if (wv_check_ioaddr(iobase[i], mac) == 0) { - dev->base_addr = iobase[i]; /* Copy base address. */ - memcpy(dev->dev_addr, mac, 6); /* Copy MAC address. */ - if (wavelan_config(dev) == 0) { + } else { /* Scan all possible addresses of the WaveLAN hardware. */ + for (i = 0; i < NELS(iobase); i++) { + dev->irq = def_irq; + if (wavelan_config(dev, iobase[i]) == 0) { #ifdef DEBUG_CALLBACK_TRACE printk(KERN_DEBUG "%s: <-wavelan_probe()\n", dev->name); #endif - return 0; + break; } } + if (i == NELS(iobase)) + r = -ENODEV; } - - /* We may have touched base_addr. Another driver may not like it. */ - dev->base_addr = base_addr; - -#ifdef DEBUG_CONFIG_INFO - printk(KERN_DEBUG "%s: wavelan_probe(): no device found\n", - dev->name); -#endif - - return -ENODEV; + if (r) + goto out; + r = register_netdev(dev); + if (r) + goto out1; + return dev; +out1: + release_region(dev->base_addr, sizeof(ha_t)); + wavelan_list = wavelan_list->next; +out: + free_netdev(dev); + return ERR_PTR(r); } /****************************** MODULE ******************************/ @@ -4311,7 +4310,6 @@ */ int init_module(void) { - mac_addr mac; /* MAC address (check WaveLAN existence) */ int ret = -EIO; /* Return error if no cards found */ int i; @@ -4337,38 +4335,28 @@ /* Loop on all possible base addresses. */ i = -1; while ((io[++i] != 0) && (i < NELS(io))) { - /* Check if there is something at this base address. */ - if (wv_check_ioaddr(io[i], mac) == 0) { - device *dev; - - /* Create device and set basic arguments. */ - dev = - kmalloc(sizeof(struct net_device), GFP_KERNEL); - if (dev == NULL) { - ret = -ENOMEM; - break; - } - memset(dev, 0x00, sizeof(struct net_device)); - memcpy(dev->name, name[i], IFNAMSIZ); /* Copy name */ - dev->base_addr = io[i]; - dev->irq = irq[i]; - dev->init = &wavelan_config; - memcpy(dev->dev_addr, mac, 6); /* Copy MAC address. */ + struct net_device *dev = alloc_etherdev(sizeof(net_local)); + if (!dev) + break; + memcpy(dev->name, name[i], IFNAMSIZ); /* Copy name */ + dev->base_addr = io[i]; + dev->irq = irq[i]; - /* Try to create the device. */ + /* Check if there is something at this base address. */ + if (wavelan_config(dev, io[i]) == 0) { if (register_netdev(dev) != 0) { - /* Deallocate everything. */ - /* Note: if dev->priv is mallocated, there is no way to fail. */ - kfree(dev); + release_region(dev->base_addr, sizeof(ha_t)); + wavelan_list = wavelan_list->next; } else { - /* If at least one device OK, we do not fail */ ret = 0; + continue; } - } /* if there is something at the address */ - } /* Loop on all addresses. */ + } + free_netdev(dev); + } #ifdef DEBUG_CONFIG_ERROR - if (wavelan_list == (net_local *) NULL) + if (!wavelan_list) printk(KERN_WARNING "WaveLAN init_module(): no device found\n"); #endif @@ -4390,26 +4378,19 @@ #endif /* Loop on all devices and release them. */ - while (wavelan_list != (net_local *) NULL) { - device *dev = wavelan_list->dev; + while (wavelan_list) { + struct net_device *dev = wavelan_list->dev; #ifdef DEBUG_CONFIG_INFO printk(KERN_DEBUG "%s: cleanup_module(): removing device at 0x%x\n", dev->name, (unsigned int) dev); #endif - - /* Release the ioport region. */ - release_region(dev->base_addr, sizeof(ha_t)); - - /* Definitely remove the device. */ unregister_netdev(dev); - /* Unlink the device. */ + release_region(dev->base_addr, sizeof(ha_t)); wavelan_list = wavelan_list->next; - /* Free pieces. */ - kfree(dev->priv); free_netdev(dev); } diff -Nru a/drivers/net/wireless/wavelan.p.h b/drivers/net/wireless/wavelan.p.h --- a/drivers/net/wireless/wavelan.p.h Thu Jan 22 18:59:26 2004 +++ b/drivers/net/wireless/wavelan.p.h Thu Jan 22 18:59:26 2004 @@ -469,7 +469,6 @@ /****************************** TYPES ******************************/ /* Shortcuts */ -typedef struct net_device device; typedef struct net_device_stats en_stats; typedef struct iw_statistics iw_stats; typedef struct iw_quality iw_qual; @@ -492,7 +491,7 @@ struct net_local { net_local * next; /* linked list of the devices */ - device * dev; /* reverse link */ + struct net_device * dev; /* reverse link */ spinlock_t spinlock; /* Serialize access to the hardware (SMP) */ en_stats stats; /* Ethernet interface statistics */ int nresets; /* number of hardware resets */ @@ -542,8 +541,8 @@ u_short), /* hacr */ wv_16_on(u_long, /* ioaddr */ u_short), /* hacr */ - wv_ints_off(device *), - wv_ints_on(device *); + wv_ints_off(struct net_device *), + wv_ints_on(struct net_device *); /* ----------------- MODEM MANAGEMENT SUBROUTINES ----------------- */ static void psa_read(u_long, /* Read the Parameter Storage Area. */ @@ -592,57 +591,57 @@ u_char *, /* b */ int); /* n */ static void - wv_ack(device *); + wv_ack(struct net_device *); static inline int - wv_synchronous_cmd(device *, + wv_synchronous_cmd(struct net_device *, const char *), - wv_config_complete(device *, + wv_config_complete(struct net_device *, u_long, net_local *); static int - wv_complete(device *, + wv_complete(struct net_device *, u_long, net_local *); static inline void - wv_82586_reconfig(device *); + wv_82586_reconfig(struct net_device *); /* ------------------- DEBUG & INFO SUBROUTINES ------------------- */ #ifdef DEBUG_I82586_SHOW static void wv_scb_show(unsigned short); #endif static inline void - wv_init_info(device *); /* display startup info */ + wv_init_info(struct net_device *); /* display startup info */ /* ------------------- IOCTL, STATS & RECONFIG ------------------- */ static en_stats * - wavelan_get_stats(device *); /* Give stats /proc/net/dev */ + wavelan_get_stats(struct net_device *); /* Give stats /proc/net/dev */ static void - wavelan_set_multicast_list(device *); + wavelan_set_multicast_list(struct net_device *); /* ----------------------- PACKET RECEPTION ----------------------- */ static inline void - wv_packet_read(device *, /* Read a packet from a frame. */ + wv_packet_read(struct net_device *, /* Read a packet from a frame. */ u_short, int), - wv_receive(device *); /* Read all packets waiting. */ + wv_receive(struct net_device *); /* Read all packets waiting. */ /* --------------------- PACKET TRANSMISSION --------------------- */ static inline int - wv_packet_write(device *, /* Write a packet to the Tx buffer. */ + wv_packet_write(struct net_device *, /* Write a packet to the Tx buffer. */ void *, short); static int wavelan_packet_xmit(struct sk_buff *, /* Send a packet. */ - device *); + struct net_device *); /* -------------------- HARDWARE CONFIGURATION -------------------- */ static inline int - wv_mmc_init(device *), /* Initialize the modem. */ - wv_ru_start(device *), /* Start the i82586 receiver unit. */ - wv_cu_start(device *), /* Start the i82586 command unit. */ - wv_82586_start(device *); /* Start the i82586. */ + wv_mmc_init(struct net_device *), /* Initialize the modem. */ + wv_ru_start(struct net_device *), /* Start the i82586 receiver unit. */ + wv_cu_start(struct net_device *), /* Start the i82586 command unit. */ + wv_82586_start(struct net_device *); /* Start the i82586. */ static void - wv_82586_config(device *); /* Configure the i82586. */ + wv_82586_config(struct net_device *); /* Configure the i82586. */ static inline void - wv_82586_stop(device *); + wv_82586_stop(struct net_device *); static int - wv_hw_reset(device *), /* Reset the WaveLAN hardware. */ + wv_hw_reset(struct net_device *), /* Reset the WaveLAN hardware. */ wv_check_ioaddr(u_long, /* ioaddr */ u_char *); /* mac address (read) */ /* ---------------------- INTERRUPT HANDLING ---------------------- */ @@ -651,14 +650,13 @@ void *, struct pt_regs *); static void - wavelan_watchdog(device *); /* transmission watchdog */ + wavelan_watchdog(struct net_device *); /* transmission watchdog */ /* ------------------- CONFIGURATION CALLBACKS ------------------- */ static int - wavelan_open(device *), /* Open the device. */ - wavelan_close(device *), /* Close the device. */ - wavelan_config(device *); /* Configure one device. */ -extern int - wavelan_probe(device *); /* See Space.c. */ + wavelan_open(struct net_device *), /* Open the device. */ + wavelan_close(struct net_device *), /* Close the device. */ + wavelan_config(struct net_device *, unsigned short);/* Configure one device. */ +extern struct net_device *wavelan_probe(int unit); /* See Space.c. */ /**************************** VARIABLES ****************************/ diff -Nru a/drivers/net/wireless/wavelan_cs.c b/drivers/net/wireless/wavelan_cs.c --- a/drivers/net/wireless/wavelan_cs.c Thu Jan 22 18:59:25 2004 +++ b/drivers/net/wireless/wavelan_cs.c Thu Jan 22 18:59:25 2004 @@ -131,7 +131,7 @@ * Read the Parameter Storage Area from the WaveLAN card's memory */ static void -psa_read(device * dev, +psa_read(struct net_device * dev, int o, /* offset in PSA */ u_char * b, /* buffer to fill */ int n) /* size to read */ @@ -155,7 +155,7 @@ * Write the Paramter Storage Area to the WaveLAN card's memory */ static void -psa_write(device * dev, +psa_write(struct net_device * dev, int o, /* Offset in psa */ u_char * b, /* Buffer in memory */ int n) /* Length of buffer */ @@ -229,7 +229,7 @@ * update the checksum field in the Wavelan's PSA */ static void -update_psa_checksum(device * dev) +update_psa_checksum(struct net_device * dev) { #ifdef SET_PSA_CRC psa_t psa; @@ -753,7 +753,7 @@ } /* Called when a WavePoint beacon is received */ -static inline void wl_roam_gather(device * dev, +static inline void wl_roam_gather(struct net_device * dev, u_char * hdr, /* Beacon header */ u_char * stats) /* SNR, Signal quality of packet */ @@ -831,7 +831,7 @@ * wv_82593_config() & wv_diag()) */ static int -wv_82593_cmd(device * dev, +wv_82593_cmd(struct net_device * dev, char * str, int cmd, int result) @@ -942,7 +942,7 @@ * status for the WaveLAN. */ static inline int -wv_diag(device * dev) +wv_diag(struct net_device * dev) { int ret = FALSE; @@ -963,7 +963,7 @@ * The return value is the address to use for next the call. */ static int -read_ringbuf(device * dev, +read_ringbuf(struct net_device * dev, int addr, char * buf, int len) @@ -1004,10 +1004,10 @@ * some delay sometime... */ static inline void -wv_82593_reconfig(device * dev) +wv_82593_reconfig(struct net_device * dev) { net_local * lp = (net_local *)dev->priv; - dev_link_t * link = ((net_local *) dev->priv)->link; + dev_link_t * link = lp->link; unsigned long flags; /* Arm the flag, will be cleard in wv_82593_config() */ @@ -1132,7 +1132,7 @@ * This function need to be completed... */ static void -wv_mmc_show(device * dev) +wv_mmc_show(struct net_device * dev) { ioaddr_t base = dev->base_addr; net_local * lp = (net_local *)dev->priv; @@ -1222,7 +1222,7 @@ * Print the formatted status of the i82593's receive unit. */ static void -wv_ru_show(device * dev) +wv_ru_show(struct net_device * dev) { net_local *lp = (net_local *) dev->priv; @@ -1241,7 +1241,7 @@ * Print the formatted status of the WaveLAN PCMCIA device driver. */ static void -wv_dev_show(device * dev) +wv_dev_show(struct net_device * dev) { printk(KERN_DEBUG "dev:"); printk(" state=%lX,", dev->state); @@ -1256,7 +1256,7 @@ * private information. */ static void -wv_local_show(device * dev) +wv_local_show(struct net_device * dev) { net_local *lp; @@ -1314,7 +1314,7 @@ * There is a lot of flag to configure it at your will... */ static inline void -wv_init_info(device * dev) +wv_init_info(struct net_device * dev) { ioaddr_t base = dev->base_addr; psa_t psa; @@ -1412,7 +1412,7 @@ * Used when the user read /proc/net/dev */ static en_stats * -wavelan_get_stats(device * dev) +wavelan_get_stats(struct net_device * dev) { #ifdef DEBUG_IOCTL_TRACE printk(KERN_DEBUG "%s: <>wavelan_get_stats()\n", dev->name); @@ -1431,7 +1431,7 @@ */ static void -wavelan_set_multicast_list(device * dev) +wavelan_set_multicast_list(struct net_device * dev) { net_local * lp = (net_local *) dev->priv; @@ -1529,7 +1529,7 @@ */ #ifdef SET_MAC_ADDRESS static int -wavelan_set_mac_address(device * dev, +wavelan_set_mac_address(struct net_device * dev, void * addr) { struct sockaddr * mac = addr; @@ -1796,7 +1796,7 @@ * Sorry, but this function really need wireless extensions... */ static inline void -wl_spy_gather(device * dev, +wl_spy_gather(struct net_device * dev, u_char * mac, /* MAC address */ u_char * stats) /* Statistics to gather */ { @@ -1823,7 +1823,7 @@ * or you may also calculate the mean and standard deviation of the level... */ static inline void -wl_his_gather(device * dev, +wl_his_gather(struct net_device * dev, u_char * stats) /* Statistics to gather */ { net_local * lp = (net_local *) dev->priv; @@ -2785,7 +2785,7 @@ * Called by /proc/net/wireless... */ static iw_stats * -wavelan_get_wireless_stats(device * dev) +wavelan_get_wireless_stats(struct net_device * dev) { ioaddr_t base = dev->base_addr; net_local * lp = (net_local *) dev->priv; @@ -2847,7 +2847,7 @@ * (called by wv_packet_rcv()) */ static inline int -wv_start_of_frame(device * dev, +wv_start_of_frame(struct net_device * dev, int rfp, /* end of frame */ int wrap) /* start of buffer */ { @@ -2909,7 +2909,7 @@ * (called by wv_packet_rcv()) */ static inline void -wv_packet_read(device * dev, +wv_packet_read(struct net_device * dev, int fd_p, int sksize) { @@ -3012,7 +3012,7 @@ * Note : the spinlock is already grabbed for us and irq are disabled. */ static inline void -wv_packet_rcv(device * dev) +wv_packet_rcv(struct net_device * dev) { ioaddr_t base = dev->base_addr; net_local * lp = (net_local *) dev->priv; @@ -3146,7 +3146,7 @@ * (called in wavelan_packet_xmit()) */ static inline void -wv_packet_write(device * dev, +wv_packet_write(struct net_device * dev, void * buf, short length) { @@ -3209,7 +3209,7 @@ */ static int wavelan_packet_xmit(struct sk_buff * skb, - device * dev) + struct net_device * dev) { net_local * lp = (net_local *)dev->priv; unsigned long flags; @@ -3273,7 +3273,7 @@ * (called by wv_hw_config()) */ static inline int -wv_mmc_init(device * dev) +wv_mmc_init(struct net_device * dev) { ioaddr_t base = dev->base_addr; psa_t psa; @@ -3467,7 +3467,7 @@ * (called in wv_ru_start() and wavelan_close() and wavelan_event()) */ static int -wv_ru_stop(device * dev) +wv_ru_stop(struct net_device * dev) { ioaddr_t base = dev->base_addr; net_local * lp = (net_local *) dev->priv; @@ -3530,7 +3530,7 @@ * (called in wv_hw_reset() & wavelan_open()) */ static int -wv_ru_start(device * dev) +wv_ru_start(struct net_device * dev) { ioaddr_t base = dev->base_addr; net_local * lp = (net_local *) dev->priv; @@ -3618,7 +3618,7 @@ * (called by wv_hw_config(), wv_82593_reconfig() & wavelan_packet_xmit()) */ static int -wv_82593_config(device * dev) +wv_82593_config(struct net_device * dev) { ioaddr_t base = dev->base_addr; net_local * lp = (net_local *) dev->priv; @@ -3792,7 +3792,7 @@ * (called by wv_config()) */ static inline int -wv_pcmcia_reset(device * dev) +wv_pcmcia_reset(struct net_device * dev) { int i; conf_reg_t reg = { 0, CS_READ, CISREG_COR, 0 }; @@ -3854,7 +3854,7 @@ * (called by wavelan_event() & wv_hw_reset()) */ static int -wv_hw_config(device * dev) +wv_hw_config(struct net_device * dev) { net_local * lp = (net_local *) dev->priv; ioaddr_t base = dev->base_addr; @@ -3961,7 +3961,7 @@ * (called by wavelan_event(), wavelan_watchdog() and wavelan_open()) */ static inline void -wv_hw_reset(device * dev) +wv_hw_reset(struct net_device * dev) { net_local * lp = (net_local *) dev->priv; @@ -4004,7 +4004,7 @@ memreq_t mem; handle = link->handle; - dev = (device *) link->priv; + dev = (struct net_device *) link->priv; #ifdef DEBUG_CONFIG_TRACE printk(KERN_DEBUG "->wv_pcmcia_config(0x%p)\n", link); @@ -4149,7 +4149,7 @@ static void wv_pcmcia_release(dev_link_t *link) { - device * dev = (device *) link->priv; + struct net_device * dev = (struct net_device *) link->priv; #ifdef DEBUG_CONFIG_TRACE printk(KERN_DEBUG "%s: -> wv_pcmcia_release(0x%p)\n", dev->name, link); @@ -4199,13 +4199,13 @@ void * dev_id, struct pt_regs * regs) { - device * dev; + struct net_device * dev; net_local * lp; ioaddr_t base; int status0; u_int tx_status; - if((dev = (device *)dev_id) == (device *) NULL) + if ((dev = dev_id) == NULL) { #ifdef DEBUG_INTERRUPT_ERROR printk(KERN_WARNING "wavelan_interrupt(): irq %d for unknown device.\n", @@ -4466,7 +4466,7 @@ * deal with the multiple Tx buffers... */ static void -wavelan_watchdog(device * dev) +wavelan_watchdog(struct net_device * dev) { net_local * lp = (net_local *) dev->priv; ioaddr_t base = dev->base_addr; @@ -4541,7 +4541,7 @@ * Called by NET3 when it "open" the device. */ static int -wavelan_open(device * dev) +wavelan_open(struct net_device * dev) { dev_link_t * link = ((net_local *) dev->priv)->link; net_local * lp = (net_local *)dev->priv; @@ -4596,7 +4596,7 @@ * Called by NET3 when it "close" the device. */ static int -wavelan_close(device * dev) +wavelan_close(struct net_device * dev) { dev_link_t * link = ((net_local *) dev->priv)->link; ioaddr_t base = dev->base_addr; @@ -4660,7 +4660,7 @@ { client_reg_t client_reg; /* Register with cardmgr */ dev_link_t * link; /* Info for cardmgr */ - device * dev; /* Interface generic data */ + struct net_device * dev; /* Interface generic data */ net_local * lp; /* Interface specific data */ int i, ret; @@ -4698,22 +4698,14 @@ dev_list = link; /* Allocate the generic data structure */ - dev = kmalloc(sizeof(struct net_device), GFP_KERNEL); + dev = alloc_etherdev(sizeof(net_local)); if (!dev) { kfree(link); return NULL; } - memset(dev, 0x00, sizeof(struct net_device)); link->priv = link->irq.Instance = dev; - /* Allocate the wavelan-specific data structure. */ - dev->priv = lp = (net_local *) kmalloc(sizeof(net_local), GFP_KERNEL); - if (!lp) { - kfree(link); - kfree(dev); - return NULL; - } - memset(lp, 0x00, sizeof(net_local)); + lp = dev->priv; /* Init specific data */ lp->configured = 0; @@ -4731,9 +4723,6 @@ lp->link = link; lp->dev = dev; - /* Standard setup for generic data */ - ether_setup(dev); - /* wavelan NET3 callbacks */ SET_MODULE_OWNER(dev); dev->open = &wavelan_open; @@ -4851,22 +4840,16 @@ /* Free pieces */ if(link->priv) { - device * dev = (device *) link->priv; + struct net_device * dev = (struct net_device *) link->priv; /* Remove ourselves from the kernel list of ethernet devices */ /* Warning : can't be called from interrupt, timer or wavelan_close() */ - if(link->dev != NULL) + if (link->dev) unregister_netdev(dev); link->dev = NULL; - - if(dev->priv) - { - /* Sound strange, but safe... */ - ((net_local *) dev->priv)->link = (dev_link_t *) NULL; - ((net_local *) dev->priv)->dev = (device *) NULL; - kfree(dev->priv); - } - kfree(link->priv); + ((net_local *) dev->priv)->link = NULL; + ((net_local *) dev->priv)->dev = NULL; + free_netdev(dev); } kfree(link); @@ -4888,7 +4871,7 @@ event_callback_args_t * args) { dev_link_t * link = (dev_link_t *) args->client_data; - device * dev = (device *) link->priv; + struct net_device * dev = (struct net_device *) link->priv; #ifdef DEBUG_CALLBACK_TRACE printk(KERN_DEBUG "->wavelan_event(): %s\n", diff -Nru a/drivers/net/wireless/wavelan_cs.p.h b/drivers/net/wireless/wavelan_cs.p.h --- a/drivers/net/wireless/wavelan_cs.p.h Thu Jan 22 18:59:26 2004 +++ b/drivers/net/wireless/wavelan_cs.p.h Thu Jan 22 18:59:26 2004 @@ -588,7 +588,6 @@ /****************************** TYPES ******************************/ /* Shortcuts */ -typedef struct net_device device; typedef struct net_device_stats en_stats; typedef struct iw_statistics iw_stats; typedef struct iw_quality iw_qual; @@ -611,7 +610,7 @@ struct net_local { dev_node_t node; /* ???? What is this stuff ???? */ - device * dev; /* Reverse link... */ + struct net_device * dev; /* Reverse link... */ spinlock_t spinlock; /* Serialize access to the hardware (SMP) */ dev_link_t * link; /* pcmcia structure */ en_stats stats; /* Ethernet interface statistics */ @@ -673,11 +672,11 @@ hacr_write_slow(u_long, u_char); static void - psa_read(device *, /* Read the Parameter Storage Area */ + psa_read(struct net_device *, /* Read the Parameter Storage Area */ int, /* offset in PSA */ u_char *, /* buffer to fill */ int), /* size to read */ - psa_write(device *, /* Write to the PSA */ + psa_write(struct net_device *, /* Write to the PSA */ int, /* Offset in psa */ u_char *, /* Buffer in memory */ int); /* Length of buffer */ @@ -707,57 +706,57 @@ int); /* number of registers */ /* ---------------------- I82593 SUBROUTINES ----------------------- */ static int - wv_82593_cmd(device *, /* synchronously send a command to i82593 */ + wv_82593_cmd(struct net_device *, /* synchronously send a command to i82593 */ char *, int, int); static inline int - wv_diag(device *); /* Diagnostique the i82593 */ + wv_diag(struct net_device *); /* Diagnostique the i82593 */ static int - read_ringbuf(device *, /* Read a receive buffer */ + read_ringbuf(struct net_device *, /* Read a receive buffer */ int, char *, int); static inline void - wv_82593_reconfig(device *); /* Reconfigure the controller */ + wv_82593_reconfig(struct net_device *); /* Reconfigure the controller */ /* ------------------- DEBUG & INFO SUBROUTINES ------------------- */ static inline void - wv_init_info(device *); /* display startup info */ + wv_init_info(struct net_device *); /* display startup info */ /* ------------------- IOCTL, STATS & RECONFIG ------------------- */ static en_stats * - wavelan_get_stats(device *); /* Give stats /proc/net/dev */ + wavelan_get_stats(struct net_device *); /* Give stats /proc/net/dev */ /* ----------------------- PACKET RECEPTION ----------------------- */ static inline int - wv_start_of_frame(device *, /* Seek beggining of current frame */ + wv_start_of_frame(struct net_device *, /* Seek beggining of current frame */ int, /* end of frame */ int); /* start of buffer */ static inline void - wv_packet_read(device *, /* Read a packet from a frame */ + wv_packet_read(struct net_device *, /* Read a packet from a frame */ int, int), - wv_packet_rcv(device *); /* Read all packets waiting */ + wv_packet_rcv(struct net_device *); /* Read all packets waiting */ /* --------------------- PACKET TRANSMISSION --------------------- */ static inline void - wv_packet_write(device *, /* Write a packet to the Tx buffer */ + wv_packet_write(struct net_device *, /* Write a packet to the Tx buffer */ void *, short); static int wavelan_packet_xmit(struct sk_buff *, /* Send a packet */ - device *); + struct net_device *); /* -------------------- HARDWARE CONFIGURATION -------------------- */ static inline int - wv_mmc_init(device *); /* Initialize the modem */ + wv_mmc_init(struct net_device *); /* Initialize the modem */ static int - wv_ru_stop(device *), /* Stop the i82593 receiver unit */ - wv_ru_start(device *); /* Start the i82593 receiver unit */ + wv_ru_stop(struct net_device *), /* Stop the i82593 receiver unit */ + wv_ru_start(struct net_device *); /* Start the i82593 receiver unit */ static int - wv_82593_config(device *); /* Configure the i82593 */ + wv_82593_config(struct net_device *); /* Configure the i82593 */ static inline int - wv_pcmcia_reset(device *); /* Reset the pcmcia interface */ + wv_pcmcia_reset(struct net_device *); /* Reset the pcmcia interface */ static int - wv_hw_config(device *); /* Reset & configure the whole hardware */ + wv_hw_config(struct net_device *); /* Reset & configure the whole hardware */ static inline void - wv_hw_reset(device *); /* Same, + start receiver unit */ + wv_hw_reset(struct net_device *); /* Same, + start receiver unit */ static inline int wv_pcmcia_config(dev_link_t *); /* Configure the pcmcia interface */ static void @@ -768,11 +767,11 @@ void *, struct pt_regs *); static void - wavelan_watchdog(device *); /* Transmission watchdog */ + wavelan_watchdog(struct net_device *); /* Transmission watchdog */ /* ------------------- CONFIGURATION CALLBACKS ------------------- */ static int - wavelan_open(device *), /* Open the device */ - wavelan_close(device *); /* Close the device */ + wavelan_open(struct net_device *), /* Open the device */ + wavelan_close(struct net_device *); /* Close the device */ static dev_link_t * wavelan_attach(void); /* Create a new device */ static void diff -Nru a/drivers/net/wireless/wl3501_cs.c b/drivers/net/wireless/wl3501_cs.c --- a/drivers/net/wireless/wl3501_cs.c Thu Jan 22 18:59:23 2004 +++ b/drivers/net/wireless/wl3501_cs.c Thu Jan 22 18:59:23 2004 @@ -1449,18 +1449,6 @@ goto out; } -/** - * wl3501_init - "initialize" board - * @dev - network device - * - * We never need to do anything when a wl3501 device is "initialized" by the net - * software, because we only register already-found cards. - */ -static int wl3501_init(struct net_device *dev) -{ - return 0; -} - struct net_device_stats *wl3501_get_stats(struct net_device *dev) { struct wl3501_card *this = dev->priv; @@ -1592,7 +1580,7 @@ *linkp = link->next; if (link->priv) - kfree(link->priv); + free_netdev(link->priv); kfree(link); out: return; @@ -2056,7 +2044,6 @@ dev = alloc_etherdev(sizeof(struct wl3501_card)); if (!dev) goto out_link; - dev->init = wl3501_init; dev->open = wl3501_open; dev->stop = wl3501_close; dev->hard_start_xmit = wl3501_hard_start_xmit; diff -Nru a/drivers/net/znet.c b/drivers/net/znet.c --- a/drivers/net/znet.c Thu Jan 22 18:59:23 2004 +++ b/drivers/net/znet.c Thu Jan 22 18:59:23 2004 @@ -372,10 +372,8 @@ struct znet_private *znet; struct net_device *dev; char *p; + int err = -ENOMEM; - if (znet_dev) /* Only look for a single adaptor */ - return -ENODEV; - /* This code scans the region 0xf0000 to 0xfffff for a "NETIDBLK". */ for(p = (char *)phys_to_virt(0xf0000); p < (char *)phys_to_virt(0x100000); p++) if (*p == 'N' && strncmp(p, "NETIDBLK", 8) == 0) @@ -387,12 +385,14 @@ return -ENODEV; } - if (!(znet_dev = dev = init_etherdev(0, sizeof(struct znet_private)))) - return -ENOMEM; + dev = alloc_etherdev(sizeof(struct znet_private)); + if (!dev) + return -ENOMEM; + + SET_MODULE_OWNER (dev); znet = dev->priv; - SET_MODULE_OWNER (dev); netinfo = (struct netidblk *)p; dev->base_addr = netinfo->iobase1; dev->irq = netinfo->irq1; @@ -430,7 +430,7 @@ znet->io_size = 2; if (!(znet->rx_start = kmalloc (DMA_BUF_SIZE, GFP_KERNEL | GFP_DMA))) - goto free_netdev; + goto free_dev; if (!(znet->tx_start = kmalloc (DMA_BUF_SIZE, GFP_KERNEL | GFP_DMA))) goto free_rx; @@ -452,19 +452,19 @@ dev->set_multicast_list = &znet_set_multicast_list; dev->tx_timeout = znet_tx_timeout; dev->watchdog_timeo = TX_TIMEOUT; - + err = register_netdev(dev); + if (err) + goto free_tx; + znet_dev = dev; return 0; free_tx: - kfree (znet->tx_start); + kfree(znet->tx_start); free_rx: - kfree (znet->rx_start); - free_netdev: - unregister_netdev (dev); - kfree (dev); - znet_dev = NULL; - - return -ENOMEM; + kfree(znet->rx_start); + free_dev: + free_netdev(dev); + return err; } @@ -934,16 +934,14 @@ static __exit void znet_cleanup (void) { -#ifdef MODULE if (znet_dev) { struct znet_private *znet = znet_dev->priv; + unregister_netdev (znet_dev); kfree (znet->rx_start); kfree (znet->tx_start); - unregister_netdev (znet_dev); free_netdev (znet_dev); } -#endif } module_init (znet_probe); diff -Nru a/drivers/net/zorro8390.c b/drivers/net/zorro8390.c --- a/drivers/net/zorro8390.c Thu Jan 22 18:59:25 2004 +++ b/drivers/net/zorro8390.c Thu Jan 22 18:59:25 2004 @@ -103,18 +103,18 @@ continue; board = z->resource.start; ioaddr = board+cards[i].offset; - dev = init_etherdev(0, 0); - SET_MODULE_OWNER(dev); + dev = alloc_ei_netdev(); if (!dev) return -ENOMEM; + SET_MODULE_OWNER(dev); if (!request_mem_region(ioaddr, NE_IO_EXTENT*2, dev->name)) { - kfree(dev); + free_netdev(dev); continue; } if ((err = zorro8390_init(dev, board, cards[i].name, ZTWO_VADDR(ioaddr)))) { release_mem_region(ioaddr, NE_IO_EXTENT*2); - kfree(dev); + free_netdev(dev); return err; } err = 0; @@ -129,6 +129,7 @@ const char *name, unsigned long ioaddr) { int i; + int err; unsigned char SA_prom[32]; int start_page, stop_page; static u32 zorro8390_offsets[16] = { @@ -195,12 +196,6 @@ i = request_irq(IRQ_AMIGA_PORTS, ei_interrupt, SA_SHIRQ, dev->name, dev); if (i) return i; - /* Allocate dev->priv and fill in 8390 specific dev fields. */ - if (ethdev_init(dev)) { - printk("Unable to get memory for dev->priv.\n"); - return -ENOMEM; - } - for(i = 0; i < ETHER_ADDR_LEN; i++) { #ifdef DEBUG printk(" %2.2x", SA_prom[i]); @@ -227,12 +222,18 @@ ei_status.reg_offset = zorro8390_offsets; dev->open = &zorro8390_open; dev->stop = &zorro8390_close; +#ifdef CONFIG_NET_POLL_CONTROLLER + dev->poll_controller = ei_poll; +#endif #ifdef MODULE ei_status.priv = (unsigned long)root_zorro8390_dev; root_zorro8390_dev = dev; #endif NS8390_init(dev, 0); - return 0; + err = register_netdev(dev); + if (err) + free_irq(IRQ_AMIGA_PORTS, dev); + return err; } static int zorro8390_open(struct net_device *dev) diff -Nru a/drivers/s390/net/lcs.c b/drivers/s390/net/lcs.c --- a/drivers/s390/net/lcs.c Thu Jan 22 18:59:23 2004 +++ b/drivers/s390/net/lcs.c Thu Jan 22 18:59:23 2004 @@ -360,7 +360,7 @@ kfree(ipm_list); } #endif - kfree(card->dev); + free_netdev(card->dev); /* Cleanup channels. */ lcs_cleanup_channel(&card->write); lcs_cleanup_channel(&card->read); @@ -1858,8 +1858,7 @@ lcs_stopcard(card); return 0; out: - lcs_cleanup_channel(&card->read); - lcs_cleanup_channel(&card->write); + lcs_cleanup_card(card); lcs_free_card(card); return -ENODEV; } diff -Nru a/drivers/s390/net/netiucv.c b/drivers/s390/net/netiucv.c --- a/drivers/s390/net/netiucv.c Thu Jan 22 18:59:25 2004 +++ b/drivers/s390/net/netiucv.c Thu Jan 22 18:59:25 2004 @@ -1473,6 +1473,14 @@ sysfs_remove_group(&dev->kobj, &netiucv_attr_group); } +/* + * XXX: Don't use sysfs unless you know WTF you are doing. + * This particular turd registers sysfs objects embedded into netiucv_priv + * which is kfreed without any regard to possible sysfs references. + * As the result, the wanker who'd decided that sysfs exports were too hip and + * cute to resist had generated a set of user-exploitable holes in this driver. + */ + static int netiucv_register_device(struct net_device *ndev, int ifno) { @@ -1592,6 +1600,22 @@ } } +static void setup_netiucv(struct net_device *dev) +{ + dev->mtu = NETIUCV_MTU_DEFAULT; + dev->hard_start_xmit = netiucv_tx; + dev->open = netiucv_open; + dev->stop = netiucv_close; + dev->get_stats = netiucv_stats; + dev->change_mtu = netiucv_change_mtu; + dev->hard_header_len = NETIUCV_HDRLEN; + dev->addr_len = 0; + dev->type = ARPHRD_SLIP; + dev->tx_queue_len = NETIUCV_QUEUELEN_DEFAULT; + dev->flags = IFF_POINTOPOINT | IFF_NOARP; + SET_MODULE_OWNER(dev); +} + /** * Allocate and initialize everything of a net device. */ @@ -1601,16 +1625,15 @@ struct netiucv_priv *privptr; int priv_size; - struct net_device *dev = kmalloc(sizeof(struct net_device), GFP_KERNEL); + struct net_device *dev = alloc_netdev(0, "", setup_netiucv); if (!dev) return NULL; - memset(dev, 0, sizeof(struct net_device)); sprintf(dev->name, "iucv%d", ifno); priv_size = sizeof(struct netiucv_priv); dev->priv = kmalloc(priv_size, GFP_KERNEL); if (dev->priv == NULL) { - kfree(dev); + free_netdev(dev); return NULL; } memset(dev->priv, 0, priv_size); @@ -1620,30 +1643,18 @@ dev_fsm, DEV_FSM_LEN, GFP_KERNEL); if (privptr->fsm == NULL) { kfree(privptr); - kfree(dev); + free_netdev(dev); return NULL; } privptr->conn = netiucv_new_connection(dev, username); if (!privptr->conn) { kfree_fsm(privptr->fsm); kfree(privptr); - kfree(dev); + free_netdev(dev); return NULL; } fsm_newstate(privptr->fsm, DEV_STATE_STOPPED); - dev->mtu = NETIUCV_MTU_DEFAULT; - dev->hard_start_xmit = netiucv_tx; - dev->open = netiucv_open; - dev->stop = netiucv_close; - dev->get_stats = netiucv_stats; - dev->change_mtu = netiucv_change_mtu; - dev->hard_header_len = NETIUCV_HDRLEN; - dev->addr_len = 0; - dev->type = ARPHRD_SLIP; - dev->tx_queue_len = NETIUCV_QUEUELEN_DEFAULT; - dev->flags = IFF_POINTOPOINT | IFF_NOARP; - SET_MODULE_OWNER(dev); return dev; } diff -Nru a/drivers/s390/net/qeth.c b/drivers/s390/net/qeth.c --- a/drivers/s390/net/qeth.c Thu Jan 22 18:59:27 2004 +++ b/drivers/s390/net/qeth.c Thu Jan 22 18:59:27 2004 @@ -6707,15 +6707,6 @@ } static void -qeth_destructor(struct net_device *dev) -{ - struct qeth_card *card; - - card = (struct qeth_card *) (dev->priv); - QETH_DBF_CARD2(0, trace, "dstr", card); -} - -static void qeth_set_multicast_list(struct net_device *dev) { struct qeth_card *card = dev->priv; @@ -7655,28 +7646,11 @@ QETH_DBF_CARD3(0, trace, "inid", card); - dev->tx_timeout = &qeth_tx_timeout; - dev->watchdog_timeo = QETH_TX_TIMEOUT; - dev->open = qeth_open; - dev->stop = qeth_stop; - dev->set_config = qeth_set_config; - dev->hard_start_xmit = qeth_hard_start_xmit; - dev->do_ioctl = qeth_do_ioctl; - dev->get_stats = qeth_get_stats; - dev->change_mtu = qeth_change_mtu; -#ifdef QETH_VLAN - dev->vlan_rx_register = qeth_vlan_rx_register; - dev->vlan_rx_kill_vid = qeth_vlan_rx_kill_vid; -#endif dev->rebuild_header = __qeth_rebuild_header_func(card); dev->hard_header = __qeth_hard_header_func(card); dev->header_cache_update = __qeth_header_cache_update_func(card); dev->hard_header_cache = __qeth_hard_header_cache_func(card); dev->hard_header_parse = NULL; - dev->destructor = qeth_destructor; - dev->set_multicast_list = qeth_set_multicast_list; - dev->set_mac_address = qeth_set_mac_address; - dev->neigh_setup = qeth_neigh_setup; dev->flags |= qeth_get_additional_dev_flags(card->type); @@ -7694,8 +7668,6 @@ dev->tx_queue_len = qeth_get_device_tx_q_len(card->type); dev->hard_header_len = qeth_get_hlen(card->link_type) + card->options.add_hhlen; - dev->addr_len = OSA_ADDR_LEN; /* is ok for eth, tr, atm lane */ - SET_MODULE_OWNER(dev); netif_start_queue(dev); dev->mtu = card->initial_mtu; @@ -8358,6 +8330,28 @@ card->options.fake_ll = DONT_FAKE_LL; } +static void qeth_setup(struct net_device *dev) +{ + dev->tx_timeout = &qeth_tx_timeout; + dev->watchdog_timeo = QETH_TX_TIMEOUT; + dev->open = qeth_open; + dev->stop = qeth_stop; + dev->set_config = qeth_set_config; + dev->hard_start_xmit = qeth_hard_start_xmit; + dev->do_ioctl = qeth_do_ioctl; + dev->get_stats = qeth_get_stats; + dev->change_mtu = qeth_change_mtu; +#ifdef QETH_VLAN + dev->vlan_rx_register = qeth_vlan_rx_register; + dev->vlan_rx_kill_vid = qeth_vlan_rx_kill_vid; +#endif + dev->set_multicast_list = qeth_set_multicast_list; + dev->set_mac_address = qeth_set_mac_address; + dev->neigh_setup = qeth_neigh_setup; + dev->addr_len = OSA_ADDR_LEN; /* is ok for eth, tr, atm lane */ + SET_MODULE_OWNER(dev); +} + static int qeth_alloc_card_stuff(struct qeth_card *card) { @@ -8385,11 +8379,9 @@ goto exit_dma2; memset(card->dma_stuff->sendbuf, 0, QETH_BUFSIZE); - card->dev = (struct net_device *) kmalloc(sizeof (struct net_device), - GFP_KERNEL); + card->dev = alloc_netdev(0, "", qeth_setup); if (!card->dev) goto exit_dev; - memset(card->dev, 0, sizeof (struct net_device)); card->stats = (struct net_device_stats *) @@ -9802,28 +9794,28 @@ qeth_get_internal_functions(void) { struct net_device *dev; - - dev = (struct net_device *) kmalloc(sizeof (struct net_device), - GFP_KERNEL); +#ifdef CONFIG_NET_ETHERNET + dev = alloc_etherdev(0); if (!dev) { PRINT_ERR("Not enough memory for internal functions.\n"); return -ENOMEM; } -#ifdef CONFIG_NET_ETHERNET - ether_setup(dev); qeth_my_eth_header = dev->hard_header; qeth_my_eth_rebuild_header = dev->rebuild_header; qeth_my_eth_header_cache = dev->hard_header_cache; qeth_my_eth_header_cache_update = dev->header_cache_update; + free_netdev(dev); #endif #ifdef CONFIG_TR - tr_setup(dev); + dev = alloc_trdev(0); + if (!dev) { + PRINT_ERR("Not enough memory for internal functions.\n"); + return -ENOMEM; + } qeth_my_tr_header = dev->hard_header; qeth_my_tr_rebuild_header = dev->rebuild_header; + free_netdev(dev); #endif - - kfree(dev); - return 0; } diff -Nru a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c --- a/drivers/usb/gadget/ether.c Thu Jan 22 18:59:26 2004 +++ b/drivers/usb/gadget/ether.c Thu Jan 22 18:59:26 2004 @@ -1782,9 +1782,7 @@ /* network device setup */ dev->net = net; SET_MODULE_OWNER (net); - net->priv = dev; strcpy (net->name, "usb%d"); - ether_setup (net); /* one random address for the gadget device ... both of these could * reasonably come from an id prom or a module parameter. diff -Nru a/drivers/usb/net/catc.c b/drivers/usb/net/catc.c --- a/drivers/usb/net/catc.c Thu Jan 22 18:59:25 2004 +++ b/drivers/usb/net/catc.c Thu Jan 22 18:59:25 2004 @@ -838,7 +838,7 @@ usb_free_urb(catc->rx_urb); if (catc->irq_urb) usb_free_urb(catc->irq_urb); - kfree(netdev); + free_netdev(netdev); kfree(catc); return -ENOMEM; } @@ -943,7 +943,7 @@ usb_free_urb(catc->tx_urb); usb_free_urb(catc->rx_urb); usb_free_urb(catc->irq_urb); - kfree(netdev); + free_netdev(netdev); kfree(catc); return -EIO; } diff -Nru a/drivers/usb/net/kaweth.c b/drivers/usb/net/kaweth.c --- a/drivers/usb/net/kaweth.c Thu Jan 22 18:59:26 2004 +++ b/drivers/usb/net/kaweth.c Thu Jan 22 18:59:26 2004 @@ -1150,7 +1150,7 @@ err_only_tx: usb_free_urb(kaweth->tx_urb); err_no_urb: - kfree(netdev); + free_netdev(netdev); err_no_netdev: kfree(kaweth); return -EIO; diff -Nru a/drivers/usb/net/pegasus.c b/drivers/usb/net/pegasus.c --- a/drivers/usb/net/pegasus.c Thu Jan 22 18:59:27 2004 +++ b/drivers/usb/net/pegasus.c Thu Jan 22 18:59:27 2004 @@ -1283,7 +1283,7 @@ usb_set_intfdata(intf, NULL); free_skb_pool(pegasus); out3: - kfree(net); + free_netdev(net); out2: free_all_urbs(pegasus); out1: diff -Nru a/drivers/usb/net/rtl8150.c b/drivers/usb/net/rtl8150.c --- a/drivers/usb/net/rtl8150.c Thu Jan 22 18:59:25 2004 +++ b/drivers/usb/net/rtl8150.c Thu Jan 22 18:59:25 2004 @@ -852,7 +852,7 @@ free_all_urbs(dev); out: kfree(dev->intr_buff); - kfree(netdev); + free_netdev(netdev); kfree(dev); return -EIO; } diff -Nru a/drivers/usb/net/usbnet.c b/drivers/usb/net/usbnet.c --- a/drivers/usb/net/usbnet.c Thu Jan 22 18:59:25 2004 +++ b/drivers/usb/net/usbnet.c Thu Jan 22 18:59:25 2004 @@ -2933,7 +2933,7 @@ if (dev->driver_info->unbind) dev->driver_info->unbind (dev, intf); - kfree(dev->net); + free_netdev(dev->net); kfree (dev); usb_put_dev (xdev); } @@ -3061,7 +3061,7 @@ if (info->unbind) info->unbind (dev, udev); out2: - kfree(net); + free_netdev(net); out1: kfree(dev); out: diff -Nru a/include/linux/arcdevice.h b/include/linux/arcdevice.h --- a/include/linux/arcdevice.h Thu Jan 22 18:59:24 2004 +++ b/include/linux/arcdevice.h Thu Jan 22 18:59:24 2004 @@ -331,6 +331,7 @@ void arcnet_unregister_proto(struct ArcProto *proto); irqreturn_t arcnet_interrupt(int irq, void *dev_id, struct pt_regs *regs); void arcdev_setup(struct net_device *dev); +struct net_device *alloc_arcdev(char *name); void arcnet_rx(struct net_device *dev, int bufnum); #endif /* __KERNEL__ */ diff -Nru a/include/linux/com20020.h b/include/linux/com20020.h --- a/include/linux/com20020.h Thu Jan 22 18:59:26 2004 +++ b/include/linux/com20020.h Thu Jan 22 18:59:26 2004 @@ -29,7 +29,6 @@ int com20020_check(struct net_device *dev); int com20020_found(struct net_device *dev, int shared); -void com20020_remove(struct net_device *dev); /* The number of low I/O ports used by the card. */ #define ARCNET_TOTAL_SIZE 8 diff -Nru a/include/linux/hdlc.h b/include/linux/hdlc.h --- a/include/linux/hdlc.h Thu Jan 22 18:59:27 2004 +++ b/include/linux/hdlc.h Thu Jan 22 18:59:27 2004 @@ -75,7 +75,7 @@ typedef struct pvc_device_struct { - struct hdlc_device_struct *master; + struct net_device *master; struct net_device *main; struct net_device *ether; /* bridged Ethernet interface */ struct pvc_device_struct *next; /* Sorted in ascending DLCI order */ @@ -96,11 +96,10 @@ typedef struct hdlc_device_struct { /* To be initialized by hardware driver */ - struct net_device netdev; /* master net device - must be first */ struct net_device_stats stats; /* used by HDLC layer to take control over HDLC device from hw driver*/ - int (*attach)(struct hdlc_device_struct *hdlc, + int (*attach)(struct net_device *dev, unsigned short encoding, unsigned short parity); /* hardware driver must handle this instead of dev->hard_start_xmit */ @@ -109,13 +108,13 @@ /* Things below are for HDLC layer internal use only */ struct { - int (*open)(struct hdlc_device_struct *hdlc); - void (*close)(struct hdlc_device_struct *hdlc); + int (*open)(struct net_device *dev); + void (*close)(struct net_device *dev); /* if open & DCD */ - void (*start)(struct hdlc_device_struct *hdlc); + void (*start)(struct net_device *dev); /* if open & !DCD */ - void (*stop)(struct hdlc_device_struct *hdlc); + void (*stop)(struct net_device *dev); void (*detach)(struct hdlc_device_struct *hdlc); int (*netif_rx)(struct sk_buff *skb); @@ -167,16 +166,17 @@ int new_mtu); }ppp; }state; + void *priv; }hdlc_device; -int hdlc_raw_ioctl(hdlc_device *hdlc, struct ifreq *ifr); -int hdlc_raw_eth_ioctl(hdlc_device *hdlc, struct ifreq *ifr); -int hdlc_cisco_ioctl(hdlc_device *hdlc, struct ifreq *ifr); -int hdlc_ppp_ioctl(hdlc_device *hdlc, struct ifreq *ifr); -int hdlc_fr_ioctl(hdlc_device *hdlc, struct ifreq *ifr); -int hdlc_x25_ioctl(hdlc_device *hdlc, struct ifreq *ifr); +int hdlc_raw_ioctl(struct net_device *dev, struct ifreq *ifr); +int hdlc_raw_eth_ioctl(struct net_device *dev, struct ifreq *ifr); +int hdlc_cisco_ioctl(struct net_device *dev, struct ifreq *ifr); +int hdlc_ppp_ioctl(struct net_device *dev, struct ifreq *ifr); +int hdlc_fr_ioctl(struct net_device *dev, struct ifreq *ifr); +int hdlc_x25_ioctl(struct net_device *dev, struct ifreq *ifr); /* Exported from hdlc.o */ @@ -185,19 +185,14 @@ int hdlc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd); /* Must be used by hardware driver on module startup/exit */ -int register_hdlc_device(hdlc_device *hdlc); -void unregister_hdlc_device(hdlc_device *hdlc); - - -static __inline__ struct net_device* hdlc_to_dev(hdlc_device *hdlc) -{ - return &hdlc->netdev; -} +int register_hdlc_device(struct net_device *dev); +void unregister_hdlc_device(struct net_device *dev); +struct net_device *alloc_hdlcdev(void *priv); static __inline__ hdlc_device* dev_to_hdlc(struct net_device *dev) { - return (hdlc_device*)dev; + return netdev_priv(dev); } @@ -207,12 +202,6 @@ } -static __inline__ const char *hdlc_to_name(hdlc_device *hdlc) -{ - return hdlc_to_dev(hdlc)->name; -} - - static __inline__ void debug_frame(const struct sk_buff *skb) { int i; @@ -229,11 +218,11 @@ /* Must be called by hardware driver when HDLC device is being opened */ -int hdlc_open(hdlc_device *hdlc); +int hdlc_open(struct net_device *dev); /* Must be called by hardware driver when HDLC device is being closed */ -void hdlc_close(hdlc_device *hdlc); +void hdlc_close(struct net_device *dev); /* Called by hardware driver when DCD line level changes */ -void hdlc_set_carrier(int on, hdlc_device *hdlc); +void hdlc_set_carrier(int on, struct net_device *dev); /* May be used by hardware driver to gain control over HDLC device */ static __inline__ void hdlc_proto_detach(hdlc_device *hdlc) @@ -241,6 +230,12 @@ if (hdlc->proto.detach) hdlc->proto.detach(hdlc); hdlc->proto.detach = NULL; +} + + +static __inline__ struct net_device_stats *hdlc_stats(struct net_device *dev) +{ + return &dev_to_hdlc(dev)->stats; } diff -Nru a/include/linux/if_bonding.h b/include/linux/if_bonding.h --- a/include/linux/if_bonding.h Thu Jan 22 18:59:26 2004 +++ b/include/linux/if_bonding.h Thu Jan 22 18:59:26 2004 @@ -1,7 +1,7 @@ /* * Bond several ethernet interfaces into a Cisco, running 'Etherchannel'. * - * + * * Portions are (c) Copyright 1995 Simon "Guru Aleph-Null" Janes * NCM: Network and Communications Management, Inc. * @@ -10,11 +10,11 @@ * * This software may be used and distributed according to the terms * of the GNU Public License, incorporated herein by reference. - * + * * 2003/03/18 - Amir Noam * - Added support for getting slave's speed and duplex via ethtool. * Needed for 802.3ad and other future modes. - * + * * 2003/03/18 - Tsippy Mendelson and * Shmulik Hen * - Enable support of modes that need to use the unique mac address of @@ -32,6 +32,9 @@ * 2003/05/01 - Amir Noam * - Added ABI version control to restore compatibility between * new/old ifenslave and new/old bonding. + * + * 2003/12/01 - Shmulik Hen + * - Code cleanup and style changes */ #ifndef _LINUX_IF_BONDING_H @@ -42,7 +45,7 @@ #include /* userland - kernel ABI version (2003/05/08) */ -#define BOND_ABI_VERSION 1 +#define BOND_ABI_VERSION 2 /* * We can remove these ioctl definitions in 2.5. People should use the @@ -77,10 +80,6 @@ #define BOND_DEFAULT_MAX_BONDS 1 /* Default maximum number of devices to support */ -#define BOND_MULTICAST_DISABLED 0 -#define BOND_MULTICAST_ACTIVE 1 -#define BOND_MULTICAST_ALL 2 - typedef struct ifbond { __s32 bond_mode; __s32 num_slaves; @@ -91,8 +90,8 @@ { __s32 slave_id; /* Used as an IN param to the BOND_SLAVE_INFO_QUERY ioctl */ char slave_name[IFNAMSIZ]; - char link; - char state; + __s8 link; + __s8 state; __u32 link_failure_count; } ifslave; @@ -115,3 +114,4 @@ * tab-width: 8 * End: */ + diff -Nru a/include/linux/if_pppvar.h b/include/linux/if_pppvar.h --- a/include/linux/if_pppvar.h Thu Jan 22 18:59:26 2004 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,138 +0,0 @@ -/* From: if_pppvar.h,v 1.2 1995/06/12 11:36:51 paulus Exp */ -/* - * if_pppvar.h - private structures and declarations for PPP. - * - * Copyright (c) 1994 The Australian National University. - * All rights reserved. - * - * Permission to use, copy, modify, and distribute this software and its - * documentation is hereby granted, provided that the above copyright - * notice appears in all copies. This software is provided without any - * warranty, express or implied. The Australian National University - * makes no representations about the suitability of this software for - * any purpose. - * - * IN NO EVENT SHALL THE AUSTRALIAN NATIONAL UNIVERSITY BE LIABLE TO ANY - * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES - * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF - * THE AUSTRALIAN NATIONAL UNIVERSITY HAVE BEEN ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES, - * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY - * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS - * ON AN "AS IS" BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO - * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, - * OR MODIFICATIONS. - * - * Copyright (c) 1989 Carnegie Mellon University. - * All rights reserved. - * - * Redistribution and use in source and binary forms are permitted - * provided that the above copyright notice and this paragraph are - * duplicated in all such forms and that any documentation, - * advertising materials, and other materials related to such - * distribution and use acknowledge that the software was developed - * by Carnegie Mellon University. The name of the - * University may not be used to endorse or promote products derived - * from this software without specific prior written permission. - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED - * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. - */ - -/* - * ==FILEVERSION 990806== - * - * NOTE TO MAINTAINERS: - * If you modify this file at all, please set the above date. - * if_pppvar.h is shipped with a PPP distribution as well as with the kernel; - * if everyone increases the FILEVERSION number above, then scripts - * can do the right thing when deciding whether to install a new if_pppvar.h - * file. Don't change the format of that line otherwise, so the - * installation script can recognize it. - */ - -/* - * Supported network protocols. These values are used for - * indexing sc_npmode. - */ - -#define NP_IP 0 /* Internet Protocol */ -#define NP_IPX 1 /* IPX protocol */ -#define NP_AT 2 /* Appletalk protocol */ -#define NP_IPV6 3 /* Internet Protocol */ -#define NUM_NP 4 /* Number of NPs. */ - -#define OBUFSIZE 256 /* # chars of output buffering */ - -/* - * Structure describing each ppp unit. - */ - -struct ppp { - int magic; /* magic value for structure */ - struct ppp *next; /* unit with next index */ - unsigned long inuse; /* are we allocated? */ - int line; /* network interface unit # */ - __u32 flags; /* miscellaneous control flags */ - int mtu; /* maximum xmit frame size */ - int mru; /* maximum receive frame size */ - struct slcompress *slcomp; /* for TCP header compression */ - struct sk_buff_head xmt_q; /* frames to send from pppd */ - struct sk_buff_head rcv_q; /* frames for pppd to read */ - unsigned long xmit_busy; /* bit 0 set when xmitter busy */ - - /* Information specific to using ppp on async serial lines. */ - struct tty_struct *tty; /* ptr to TTY structure */ - struct tty_struct *backup_tty; /* TTY to use if tty gets closed */ - __u8 escape; /* 0x20 if prev char was PPP_ESC */ - __u8 toss; /* toss this frame */ - volatile __u8 tty_pushing; /* internal state flag */ - volatile __u8 woke_up; /* internal state flag */ - __u32 xmit_async_map[8]; /* 1 bit means that given control - character is quoted on output*/ - __u32 recv_async_map; /* 1 bit means that given control - character is ignored on input*/ - __u32 bytes_sent; /* Bytes sent on frame */ - __u32 bytes_rcvd; /* Bytes recvd on frame */ - - /* Async transmission information */ - struct sk_buff *tpkt; /* frame currently being sent */ - int tpkt_pos; /* how much of it we've done */ - __u16 tfcs; /* FCS so far for it */ - unsigned char *optr; /* where we're up to in sending */ - unsigned char *olim; /* points past last valid char */ - - /* Async reception information */ - struct sk_buff *rpkt; /* frame currently being rcvd */ - __u16 rfcs; /* FCS so far of rpkt */ - - /* Queues for select() functionality */ - wait_queue_head_t read_wait; /* queue for reading processes */ - - /* info for detecting idle channels */ - unsigned long last_xmit; /* time of last transmission */ - unsigned long last_recv; /* time last packet received */ - - /* Statistic information */ - struct pppstat stats; /* statistic information */ - - /* PPP compression protocol information */ - struct compressor *sc_xcomp; /* transmit compressor */ - void *sc_xc_state; /* transmit compressor state */ - struct compressor *sc_rcomp; /* receive decompressor */ - void *sc_rc_state; /* receive decompressor state */ - - enum NPmode sc_npmode[NUM_NP]; /* what to do with each NP */ - int sc_xfer; /* PID of reserved PPP table */ - char name[16]; /* space for unit name */ - struct net_device dev; /* net device structure */ - struct net_device_stats estats; /* more detailed stats */ - - /* tty output buffer */ - unsigned char obuf[OBUFSIZE]; /* buffer for characters to send */ -}; - -#define PPP_MAGIC 0x5002 -#define PPP_VERSION "2.3.7" diff -Nru a/include/linux/isdn.h b/include/linux/isdn.h --- a/include/linux/isdn.h Thu Jan 22 18:59:27 2004 +++ b/include/linux/isdn.h Thu Jan 22 18:59:27 2004 @@ -192,7 +192,6 @@ #include #include -#include #include #endif diff -Nru a/include/linux/lapb.h b/include/linux/lapb.h --- a/include/linux/lapb.h Thu Jan 22 18:59:26 2004 +++ b/include/linux/lapb.h Thu Jan 22 18:59:26 2004 @@ -24,12 +24,12 @@ #define LAPB_DCE 0x04 struct lapb_register_struct { - void (*connect_confirmation)(void *token, int reason); - void (*connect_indication)(void *token, int reason); - void (*disconnect_confirmation)(void *token, int reason); - void (*disconnect_indication)(void *token, int reason); - int (*data_indication)(void *token, struct sk_buff *skb); - void (*data_transmit)(void *token, struct sk_buff *skb); + void (*connect_confirmation)(struct net_device *dev, int reason); + void (*connect_indication)(struct net_device *dev, int reason); + void (*disconnect_confirmation)(struct net_device *dev, int reason); + void (*disconnect_indication)(struct net_device *dev, int reason); + int (*data_indication)(struct net_device *dev, struct sk_buff *skb); + void (*data_transmit)(struct net_device *dev, struct sk_buff *skb); }; struct lapb_parms_struct { @@ -44,13 +44,13 @@ unsigned int mode; }; -extern int lapb_register(void *token, struct lapb_register_struct *callbacks); -extern int lapb_unregister(void *token); -extern int lapb_getparms(void *token, struct lapb_parms_struct *parms); -extern int lapb_setparms(void *token, struct lapb_parms_struct *parms); -extern int lapb_connect_request(void *token); -extern int lapb_disconnect_request(void *token); -extern int lapb_data_request(void *token, struct sk_buff *skb); -extern int lapb_data_received(void *token, struct sk_buff *skb); +extern int lapb_register(struct net_device *dev, struct lapb_register_struct *callbacks); +extern int lapb_unregister(struct net_device *dev); +extern int lapb_getparms(struct net_device *dev, struct lapb_parms_struct *parms); +extern int lapb_setparms(struct net_device *dev, struct lapb_parms_struct *parms); +extern int lapb_connect_request(struct net_device *dev); +extern int lapb_disconnect_request(struct net_device *dev); +extern int lapb_data_request(struct net_device *dev, struct sk_buff *skb); +extern int lapb_data_received(struct net_device *dev, struct sk_buff *skb); #endif diff -Nru a/include/linux/netdevice.h b/include/linux/netdevice.h --- a/include/linux/netdevice.h Thu Jan 22 18:59:26 2004 +++ b/include/linux/netdevice.h Thu Jan 22 18:59:26 2004 @@ -452,6 +452,12 @@ unsigned char *haddr); int (*neigh_setup)(struct net_device *dev, struct neigh_parms *); int (*accept_fastpath)(struct net_device *, struct dst_entry*); +#ifdef CONFIG_NETPOLL_RX + int netpoll_rx; +#endif +#ifdef CONFIG_NET_POLL_CONTROLLER + void (*poll_controller)(struct net_device *dev); +#endif /* bridge stuff */ struct net_bridge_port *br_port; @@ -470,8 +476,15 @@ /* class/net/name entry */ struct class_device class_dev; struct net_device_stats* (*last_stats)(struct net_device *); + /* how much padding had been added by alloc_netdev() */ + int padded; }; +static inline void *netdev_priv(struct net_device *dev) +{ + return (char *)dev + ((sizeof(struct net_device) + 31) & ~31); +} + #define SET_MODULE_OWNER(dev) do { } while (0) /* Set the sysfs physical device reference for the network logical device * if set prior to registration will cause a symlink during initialization. @@ -496,6 +509,7 @@ extern int netdev_boot_setup_add(char *name, struct ifmap *map); extern int netdev_boot_setup_check(struct net_device *dev); +extern unsigned long netdev_boot_base(const char *prefix, int unit); extern struct net_device *dev_getbyhwaddr(unsigned short type, char *hwaddr); extern struct net_device *__dev_getfirstbyhwtype(unsigned short type); extern struct net_device *dev_getfirstbyhwtype(unsigned short type); @@ -533,6 +547,9 @@ extern struct net_device *dev_get_by_index(int ifindex); extern struct net_device *__dev_get_by_index(int ifindex); extern int dev_restart(struct net_device *dev); +#ifdef CONFIG_NETPOLL_TRAP +extern int netpoll_trap(void); +#endif typedef int gifconf_func_t(struct net_device * dev, char * bufptr, int len); extern int register_gifconf(unsigned int family, gifconf_func_t * gifconf); @@ -591,12 +608,20 @@ static inline void netif_wake_queue(struct net_device *dev) { +#ifdef CONFIG_NETPOLL_TRAP + if (netpoll_trap()) + return; +#endif if (test_and_clear_bit(__LINK_STATE_XOFF, &dev->state)) __netif_schedule(dev); } static inline void netif_stop_queue(struct net_device *dev) { +#ifdef CONFIG_NETPOLL_TRAP + if (netpoll_trap()) + return; +#endif set_bit(__LINK_STATE_XOFF, &dev->state); } diff -Nru a/include/linux/netpoll.h b/include/linux/netpoll.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/linux/netpoll.h Thu Jan 22 18:59:27 2004 @@ -0,0 +1,38 @@ +/* + * Common code for low-level network console, dump, and debugger code + * + * Derived from netconsole, kgdb-over-ethernet, and netdump patches + */ + +#ifndef _LINUX_NETPOLL_H +#define _LINUX_NETPOLL_H + +#include +#include +#include +#include + +struct netpoll; + +struct netpoll { + struct net_device *dev; + char dev_name[16], *name; + void (*rx_hook)(struct netpoll *, int, char *, int); + u32 local_ip, remote_ip; + u16 local_port, remote_port; + unsigned char local_mac[6], remote_mac[6]; + struct list_head rx_list; +}; + +void netpoll_poll(struct netpoll *np); +void netpoll_send_skb(struct netpoll *np, struct sk_buff *skb); +void netpoll_send_udp(struct netpoll *np, const char *msg, int len); +int netpoll_parse_options(struct netpoll *np, char *opt); +int netpoll_setup(struct netpoll *np); +int netpoll_trap(void); +void netpoll_set_trap(int trap); +void netpoll_cleanup(struct netpoll *np); +int netpoll_rx(struct sk_buff *skb); + + +#endif diff -Nru a/include/linux/pci_ids.h b/include/linux/pci_ids.h --- a/include/linux/pci_ids.h Thu Jan 22 18:59:25 2004 +++ b/include/linux/pci_ids.h Thu Jan 22 18:59:25 2004 @@ -633,6 +633,8 @@ #define PCI_DEVICE_ID_HP_TACHLITE 0x1029 #define PCI_DEVICE_ID_HP_J2585A 0x1030 #define PCI_DEVICE_ID_HP_J2585B 0x1031 +#define PCI_DEVICE_ID_HP_J2973A 0x1040 +#define PCI_DEVICE_ID_HP_J2970A 0x1042 #define PCI_DEVICE_ID_HP_DIVA 0x1048 #define PCI_DEVICE_ID_HP_DIVA_TOSCA1 0x1049 #define PCI_DEVICE_ID_HP_DIVA_TOSCA2 0x104A diff -Nru a/include/linux/ppp.h b/include/linux/ppp.h --- a/include/linux/ppp.h Thu Jan 22 18:59:23 2004 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,4 +0,0 @@ -/* - * Back compatibility for a while. - */ -#include diff -Nru a/include/net/atmclip.h b/include/net/atmclip.h --- a/include/net/atmclip.h Thu Jan 22 18:59:26 2004 +++ b/include/net/atmclip.h Thu Jan 22 18:59:26 2004 @@ -44,7 +44,7 @@ }; -#define PRIV(dev) ((struct clip_priv *) ((struct net_device *) (dev)+1)) +#define PRIV(dev) ((struct clip_priv *) netdev_priv(dev)) struct clip_priv { diff -Nru a/include/net/lapb.h b/include/net/lapb.h --- a/include/net/lapb.h Thu Jan 22 18:59:26 2004 +++ b/include/net/lapb.h Thu Jan 22 18:59:26 2004 @@ -80,7 +80,7 @@ */ struct lapb_cb { struct list_head node; - void *token; + struct net_device *dev; /* Link status fields */ unsigned int mode; diff -Nru a/net/8021q/vlan.c b/net/8021q/vlan.c --- a/net/8021q/vlan.c Thu Jan 22 18:59:26 2004 +++ b/net/8021q/vlan.c Thu Jan 22 18:59:26 2004 @@ -566,7 +566,7 @@ goto out_put_dev; out_free_newdev: - kfree(new_dev); + free_netdev(new_dev); out_unlock: rtnl_unlock(); diff -Nru a/net/Kconfig b/net/Kconfig --- a/net/Kconfig Thu Jan 22 18:59:23 2004 +++ b/net/Kconfig Thu Jan 22 18:59:23 2004 @@ -664,4 +664,20 @@ source "net/bluetooth/Kconfig" +config NETPOLL + def_bool NETCONSOLE + +config NETPOLL_RX + bool "Netpoll support for trapping incoming packets" + default n + depends on NETPOLL + +config NETPOLL_TRAP + bool "Netpoll traffic trapping" + default n + depends on NETPOLL + +config NET_POLL_CONTROLLER + def_bool NETPOLL + endmenu diff -Nru a/net/atm/clip.c b/net/atm/clip.c --- a/net/atm/clip.c Thu Jan 22 18:59:26 2004 +++ b/net/atm/clip.c Thu Jan 22 18:59:26 2004 @@ -563,32 +563,20 @@ } -static int clip_init(struct net_device *dev) +static void clip_setup(struct net_device *dev) { - DPRINTK("clip_init %s\n",dev->name); dev->hard_start_xmit = clip_start_xmit; /* sg_xmit ... */ - dev->hard_header = NULL; - dev->rebuild_header = NULL; - dev->set_mac_address = NULL; - dev->hard_header_parse = NULL; - dev->hard_header_cache = NULL; - dev->header_cache_update = NULL; - dev->change_mtu = NULL; - dev->do_ioctl = NULL; dev->get_stats = clip_get_stats; dev->type = ARPHRD_ATM; dev->hard_header_len = RFC1483LLC_LEN; dev->mtu = RFC1626_MTU; - dev->addr_len = 0; dev->tx_queue_len = 100; /* "normal" queue (packets) */ /* When using a "real" qdisc, the qdisc determines the queue */ /* length. tx_queue_len is only used for the default case, */ /* without any more elaborate queuing. 100 is a reasonable */ /* compromise between decent burst-tolerance and protection */ /* against memory hogs. */ - dev->flags = 0; - return 0; } @@ -608,18 +596,16 @@ if (PRIV(dev)->number >= number) number = PRIV(dev)->number+1; } - dev = kmalloc(sizeof(struct net_device)+sizeof(struct clip_priv), - GFP_KERNEL); - if (!dev) return -ENOMEM; - memset(dev,0,sizeof(struct net_device)+sizeof(struct clip_priv)); + dev = alloc_netdev(sizeof(struct clip_priv), "", clip_setup); + if (!dev) + return -ENOMEM; clip_priv = PRIV(dev); sprintf(dev->name,"atm%d",number); - dev->init = clip_init; spin_lock_init(&clip_priv->xoff_lock); clip_priv->number = number; error = register_netdev(dev); if (error) { - kfree(dev); + free_netdev(dev); return error; } clip_priv->next = clip_devs; @@ -634,7 +620,7 @@ { /* ignore non-CLIP devices */ if (((struct net_device *) dev)->type != ARPHRD_ATM || - ((struct net_device *) dev)->init != clip_init) + ((struct net_device *) dev)->hard_start_xmit != clip_start_xmit) return NOTIFY_DONE; switch (event) { case NETDEV_UP: diff -Nru a/net/atm/lec.c b/net/atm/lec.c --- a/net/atm/lec.c Thu Jan 22 18:59:25 2004 +++ b/net/atm/lec.c Thu Jan 22 18:59:25 2004 @@ -798,7 +798,7 @@ return -ENOMEM; snprintf(dev_lec[i]->name, IFNAMSIZ, "lec%d", i); if (register_netdev(dev_lec[i])) { - kfree(dev_lec[i]); + free_netdev(dev_lec[i]); return -EINVAL; } diff -Nru a/net/bluetooth/bnep/core.c b/net/bluetooth/bnep/core.c --- a/net/bluetooth/bnep/core.c Thu Jan 22 18:59:26 2004 +++ b/net/bluetooth/bnep/core.c Thu Jan 22 18:59:26 2004 @@ -501,7 +501,7 @@ __bnep_unlink_session(s); up_write(&bnep_session_sem); - kfree(dev); + free_netdev(dev); return 0; } @@ -588,7 +588,7 @@ failed: up_write(&bnep_session_sem); - kfree(dev); + free_netdev(dev); return err; } diff -Nru a/net/bridge/br_if.c b/net/bridge/br_if.c --- a/net/bridge/br_if.c Thu Jan 22 18:59:27 2004 +++ b/net/bridge/br_if.c Thu Jan 22 18:59:27 2004 @@ -172,7 +172,7 @@ ret = register_netdev(br->dev); if (ret) - kfree(br->dev); + free_netdev(br->dev); return ret; } diff -Nru a/net/core/Makefile b/net/core/Makefile --- a/net/core/Makefile Thu Jan 22 18:59:26 2004 +++ b/net/core/Makefile Thu Jan 22 18:59:26 2004 @@ -13,3 +13,4 @@ obj-$(CONFIG_NET_DIVERT) += dv.o obj-$(CONFIG_NET_PKTGEN) += pktgen.o obj-$(CONFIG_NET_RADIO) += wireless.o +obj-$(CONFIG_NETPOLL) += netpoll.o diff -Nru a/net/core/dev.c b/net/core/dev.c --- a/net/core/dev.c Thu Jan 22 18:59:25 2004 +++ b/net/core/dev.c Thu Jan 22 18:59:25 2004 @@ -105,6 +105,7 @@ #include #include #include +#include #ifdef CONFIG_NET_RADIO #include /* Note : will define WIRELESS_EXT */ #include @@ -371,6 +372,30 @@ return 0; } + +/** + * netdev_boot_base - get address from boot time settings + * @prefix: prefix for network device + * @unit: id for network device + * + * Check boot time settings for the base address of device. + * The found settings are set for the device to be used + * later in the device probing. + * Returns 0 if no settings found. + */ +unsigned long netdev_boot_base(const char *prefix, int unit) +{ + const struct netdev_boot_setup *s = dev_boot_setup; + char name[IFNAMSIZ]; + int i; + + sprintf(name, "%s%d", prefix, unit); + for (i = 0; i < NETDEV_BOOT_SETUP_MAX; i++) + if (!strcmp(name, s[i].name)) + return s[i].map.base_addr; + return 0; +} + /* * Saves at boot time configured settings for any netdevice. */ @@ -1473,6 +1498,13 @@ struct softnet_data *queue; unsigned long flags; +#ifdef CONFIG_NETPOLL_RX + if (skb->dev->netpoll_rx && netpoll_rx(skb)) { + kfree_skb(skb); + return NET_RX_DROP; + } +#endif + if (!skb->stamp.tv_sec) do_gettimeofday(&skb->stamp); @@ -1628,6 +1660,13 @@ int ret = NET_RX_DROP; unsigned short type = skb->protocol; +#ifdef CONFIG_NETPOLL_RX + if (skb->dev->netpoll_rx && skb->dev->poll && netpoll_rx(skb)) { + kfree_skb(skb); + return NET_RX_DROP; + } +#endif + if (!skb->stamp.tv_sec) do_gettimeofday(&skb->stamp); @@ -2936,7 +2975,7 @@ { /* Compatiablity with error handling in drivers */ if (dev->reg_state == NETREG_UNINITIALIZED) { - kfree(dev); + kfree((char *)dev - dev->padded); return; } diff -Nru a/net/core/net-sysfs.c b/net/core/net-sysfs.c --- a/net/core/net-sysfs.c Thu Jan 22 18:59:26 2004 +++ b/net/core/net-sysfs.c Thu Jan 22 18:59:26 2004 @@ -372,7 +372,7 @@ BUG_ON(dev->reg_state != NETREG_RELEASED); - kfree(dev); + kfree((char *)dev - dev->padded); } static struct class net_class = { diff -Nru a/net/core/netpoll.c b/net/core/netpoll.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/net/core/netpoll.c Thu Jan 22 18:59:27 2004 @@ -0,0 +1,651 @@ +/* + * Common framework for low-level network console, dump, and debugger code + * + * Sep 8 2003 Matt Mackall + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * We maintain a small pool of fully-sized skbs, to make sure the + * message gets out even in extreme OOM situations. + */ + +#define MAX_SKBS 32 +#define MAX_UDP_CHUNK 1460 + +static spinlock_t skb_list_lock = SPIN_LOCK_UNLOCKED; +static int nr_skbs; +static struct sk_buff *skbs; + +static spinlock_t rx_list_lock = SPIN_LOCK_UNLOCKED; +static LIST_HEAD(rx_list); + +static int trapped; + +#define MAX_SKB_SIZE \ + (MAX_UDP_CHUNK + sizeof(struct udphdr) + \ + sizeof(struct iphdr) + sizeof(struct ethhdr)) + +static void zap_completion_queue(void); + +static int checksum_udp(struct sk_buff *skb, struct udphdr *uh, + unsigned short ulen, u32 saddr, u32 daddr) +{ + if (uh->check == 0) + return 0; + + if (skb->ip_summed == CHECKSUM_HW) + return csum_tcpudp_magic( + saddr, daddr, ulen, IPPROTO_UDP, skb->csum); + + skb->csum = csum_tcpudp_nofold(saddr, daddr, ulen, IPPROTO_UDP, 0); + + return csum_fold(skb_checksum(skb, 0, skb->len, skb->csum)); +} + +void netpoll_poll(struct netpoll *np) +{ + int budget = 1; + + if(!np->dev || !netif_running(np->dev) || !np->dev->poll_controller) + return; + + /* Process pending work on NIC */ + np->dev->poll_controller(np->dev); + + /* If scheduling is stopped, tickle NAPI bits */ + if(trapped && np->dev->poll && + test_bit(__LINK_STATE_RX_SCHED, &np->dev->state)) + np->dev->poll(np->dev, &budget); + zap_completion_queue(); +} + +static void refill_skbs(void) +{ + struct sk_buff *skb; + unsigned long flags; + + spin_lock_irqsave(&skb_list_lock, flags); + while (nr_skbs < MAX_SKBS) { + skb = alloc_skb(MAX_SKB_SIZE, GFP_ATOMIC); + if (!skb) + break; + + skb->next = skbs; + skbs = skb; + nr_skbs++; + } + spin_unlock_irqrestore(&skb_list_lock, flags); +} + +static void zap_completion_queue(void) +{ + unsigned long flags; + struct softnet_data *sd = &get_cpu_var(softnet_data); + + if (sd->completion_queue) { + struct sk_buff *clist; + + local_irq_save(flags); + clist = sd->completion_queue; + sd->completion_queue = NULL; + local_irq_restore(flags); + + while (clist != NULL) { + struct sk_buff *skb = clist; + clist = clist->next; + __kfree_skb(skb); + } + } + + put_cpu_var(softnet_data); +} + +static struct sk_buff * find_skb(struct netpoll *np, int len, int reserve) +{ + int once = 1, count = 0; + unsigned long flags; + struct sk_buff *skb = NULL; + + zap_completion_queue(); +repeat: + if (nr_skbs < MAX_SKBS) + refill_skbs(); + + skb = alloc_skb(len, GFP_ATOMIC); + + if (!skb) { + spin_lock_irqsave(&skb_list_lock, flags); + skb = skbs; + if (skb) + skbs = skb->next; + skb->next = NULL; + nr_skbs--; + spin_unlock_irqrestore(&skb_list_lock, flags); + } + + if(!skb) { + count++; + if (once && (count == 1000000)) { + printk("out of netpoll skbs!\n"); + once = 0; + } + netpoll_poll(np); + goto repeat; + } + + atomic_set(&skb->users, 1); + skb_reserve(skb, reserve); + return skb; +} + +void netpoll_send_skb(struct netpoll *np, struct sk_buff *skb) +{ + int status; + +repeat: + if(!np || !np->dev || !netif_running(np->dev)) { + __kfree_skb(skb); + return; + } + + spin_lock(&np->dev->xmit_lock); + np->dev->xmit_lock_owner = smp_processor_id(); + + if (netif_queue_stopped(np->dev)) { + np->dev->xmit_lock_owner = -1; + spin_unlock(&np->dev->xmit_lock); + + netpoll_poll(np); + goto repeat; + } + + status = np->dev->hard_start_xmit(skb, np->dev); + np->dev->xmit_lock_owner = -1; + spin_unlock(&np->dev->xmit_lock); + + /* transmit busy */ + if(status) + goto repeat; +} + +void netpoll_send_udp(struct netpoll *np, const char *msg, int len) +{ + int total_len, eth_len, ip_len, udp_len; + struct sk_buff *skb; + struct udphdr *udph; + struct iphdr *iph; + struct ethhdr *eth; + + udp_len = len + sizeof(*udph); + ip_len = eth_len = udp_len + sizeof(*iph); + total_len = eth_len + ETH_HLEN; + + skb = find_skb(np, total_len, total_len - len); + if (!skb) + return; + + memcpy(skb->data, msg, len); + skb->len += len; + + udph = (struct udphdr *) skb_push(skb, sizeof(*udph)); + udph->source = htons(np->local_port); + udph->dest = htons(np->remote_port); + udph->len = htons(udp_len); + udph->check = 0; + + iph = (struct iphdr *)skb_push(skb, sizeof(*iph)); + + iph->version = 4; + iph->ihl = 5; + iph->tos = 0; + iph->tot_len = htons(ip_len); + iph->id = 0; + iph->frag_off = 0; + iph->ttl = 64; + iph->protocol = IPPROTO_UDP; + iph->check = 0; + iph->saddr = htonl(np->local_ip); + iph->daddr = htonl(np->remote_ip); + iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl); + + eth = (struct ethhdr *) skb_push(skb, ETH_HLEN); + + eth->h_proto = htons(ETH_P_IP); + memcpy(eth->h_source, np->local_mac, 6); + memcpy(eth->h_dest, np->remote_mac, 6); + + netpoll_send_skb(np, skb); +} + +static void arp_reply(struct sk_buff *skb) +{ + struct in_device *in_dev = (struct in_device *) skb->dev->ip_ptr; + struct arphdr *arp; + unsigned char *arp_ptr, *sha, *tha; + int size, type = ARPOP_REPLY, ptype = ETH_P_ARP; + u32 sip, tip; + struct sk_buff *send_skb; + unsigned long flags; + struct list_head *p; + struct netpoll *np = 0; + + spin_lock_irqsave(&rx_list_lock, flags); + list_for_each(p, &rx_list) { + np = list_entry(p, struct netpoll, rx_list); + if ( np->dev == skb->dev ) + break; + np = 0; + } + spin_unlock_irqrestore(&rx_list_lock, flags); + + if (!np) return; + + /* No arp on this interface */ + if (!in_dev || skb->dev->flags & IFF_NOARP) + return; + + if (!pskb_may_pull(skb, (sizeof(struct arphdr) + + (2 * skb->dev->addr_len) + + (2 * sizeof(u32))))) + return; + + skb->h.raw = skb->nh.raw = skb->data; + arp = skb->nh.arph; + + if ((arp->ar_hrd != htons(ARPHRD_ETHER) && + arp->ar_hrd != htons(ARPHRD_IEEE802)) || + arp->ar_pro != htons(ETH_P_IP) || + arp->ar_op != htons(ARPOP_REQUEST)) + return; + + arp_ptr= (unsigned char *)(arp+1); + sha = arp_ptr; + arp_ptr += skb->dev->addr_len; + memcpy(&sip, arp_ptr, 4); + arp_ptr += 4; + tha = arp_ptr; + arp_ptr += skb->dev->addr_len; + memcpy(&tip, arp_ptr, 4); + + /* Should we ignore arp? */ + if (tip != in_dev->ifa_list->ifa_address || + LOOPBACK(tip) || MULTICAST(tip)) + return; + + + size = sizeof(struct arphdr) + 2 * (skb->dev->addr_len + 4); + send_skb = find_skb(np, size + LL_RESERVED_SPACE(np->dev), + LL_RESERVED_SPACE(np->dev)); + + if (!send_skb) + return; + + send_skb->nh.raw = send_skb->data; + arp = (struct arphdr *) skb_put(send_skb, size); + send_skb->dev = skb->dev; + send_skb->protocol = htons(ETH_P_ARP); + + /* Fill the device header for the ARP frame */ + + if (np->dev->hard_header && + np->dev->hard_header(send_skb, skb->dev, ptype, + np->remote_mac, np->local_mac, + send_skb->len) < 0) { + kfree_skb(send_skb); + return; + } + + /* + * Fill out the arp protocol part. + * + * we only support ethernet device type, + * which (according to RFC 1390) should always equal 1 (Ethernet). + */ + + arp->ar_hrd = htons(np->dev->type); + arp->ar_pro = htons(ETH_P_IP); + arp->ar_hln = np->dev->addr_len; + arp->ar_pln = 4; + arp->ar_op = htons(type); + + arp_ptr=(unsigned char *)(arp + 1); + memcpy(arp_ptr, np->dev->dev_addr, np->dev->addr_len); + arp_ptr += np->dev->addr_len; + memcpy(arp_ptr, &tip, 4); + arp_ptr += 4; + memcpy(arp_ptr, np->local_mac, np->dev->addr_len); + arp_ptr += np->dev->addr_len; + memcpy(arp_ptr, &sip, 4); + + netpoll_send_skb(np, send_skb); +} + +int netpoll_rx(struct sk_buff *skb) +{ + int proto, len, ulen; + struct iphdr *iph; + struct udphdr *uh; + struct netpoll *np; + struct list_head *p; + unsigned long flags; + + if (skb->dev->type != ARPHRD_ETHER) + goto out; + + /* check if netpoll clients need ARP */ + if (skb->protocol == __constant_htons(ETH_P_ARP) && trapped) { + arp_reply(skb); + return 1; + } + + proto = ntohs(skb->mac.ethernet->h_proto); + if (proto != ETH_P_IP) + goto out; + if (skb->pkt_type == PACKET_OTHERHOST) + goto out; + if (skb_shared(skb)) + goto out; + + iph = (struct iphdr *)skb->data; + if (!pskb_may_pull(skb, sizeof(struct iphdr))) + goto out; + if (iph->ihl < 5 || iph->version != 4) + goto out; + if (!pskb_may_pull(skb, iph->ihl*4)) + goto out; + if (ip_fast_csum((u8 *)iph, iph->ihl) != 0) + goto out; + + len = ntohs(iph->tot_len); + if (skb->len < len || len < iph->ihl*4) + goto out; + + if (iph->protocol != IPPROTO_UDP) + goto out; + + len -= iph->ihl*4; + uh = (struct udphdr *)(((char *)iph) + iph->ihl*4); + ulen = ntohs(uh->len); + + if (ulen != len) + goto out; + if (checksum_udp(skb, uh, ulen, iph->saddr, iph->daddr) < 0) + goto out; + + spin_lock_irqsave(&rx_list_lock, flags); + list_for_each(p, &rx_list) { + np = list_entry(p, struct netpoll, rx_list); + if (np->dev && np->dev != skb->dev) + continue; + if (np->local_ip && np->local_ip != ntohl(iph->daddr)) + continue; + if (np->remote_ip && np->remote_ip != ntohl(iph->saddr)) + continue; + if (np->local_port && np->local_port != ntohs(uh->dest)) + continue; + + spin_unlock_irqrestore(&rx_list_lock, flags); + + if (np->rx_hook) + np->rx_hook(np, ntohs(uh->source), + (char *)(uh+1), + ulen - sizeof(struct udphdr)); + + return 1; + } + spin_unlock_irqrestore(&rx_list_lock, flags); + +out: + return trapped; +} + +int netpoll_parse_options(struct netpoll *np, char *opt) +{ + char *cur=opt, *delim; + + if(*cur != '@') { + if ((delim = strchr(cur, '@')) == NULL) + goto parse_failed; + *delim=0; + np->local_port=simple_strtol(cur, 0, 10); + cur=delim; + } + cur++; + printk(KERN_INFO "%s: local port %d\n", np->name, np->local_port); + + if(*cur != '/') { + if ((delim = strchr(cur, '/')) == NULL) + goto parse_failed; + *delim=0; + np->local_ip=ntohl(in_aton(cur)); + cur=delim; + + printk(KERN_INFO "%s: local IP %d.%d.%d.%d\n", + np->name, HIPQUAD(np->local_ip)); + } + cur++; + + if ( *cur != ',') { + /* parse out dev name */ + if ((delim = strchr(cur, ',')) == NULL) + goto parse_failed; + *delim=0; + strlcpy(np->dev_name, cur, sizeof(np->dev_name)); + cur=delim; + } + cur++; + + printk(KERN_INFO "%s: interface %s\n", np->name, np->dev_name); + + if ( *cur != '@' ) { + /* dst port */ + if ((delim = strchr(cur, '@')) == NULL) + goto parse_failed; + *delim=0; + np->remote_port=simple_strtol(cur, 0, 10); + cur=delim; + } + cur++; + printk(KERN_INFO "%s: remote port %d\n", np->name, np->remote_port); + + /* dst ip */ + if ((delim = strchr(cur, '/')) == NULL) + goto parse_failed; + *delim=0; + np->remote_ip=ntohl(in_aton(cur)); + cur=delim+1; + + printk(KERN_INFO "%s: remote IP %d.%d.%d.%d\n", + np->name, HIPQUAD(np->remote_ip)); + + if( *cur != 0 ) + { + /* MAC address */ + if ((delim = strchr(cur, ':')) == NULL) + goto parse_failed; + *delim=0; + np->remote_mac[0]=simple_strtol(cur, 0, 16); + cur=delim+1; + if ((delim = strchr(cur, ':')) == NULL) + goto parse_failed; + *delim=0; + np->remote_mac[1]=simple_strtol(cur, 0, 16); + cur=delim+1; + if ((delim = strchr(cur, ':')) == NULL) + goto parse_failed; + *delim=0; + np->remote_mac[2]=simple_strtol(cur, 0, 16); + cur=delim+1; + if ((delim = strchr(cur, ':')) == NULL) + goto parse_failed; + *delim=0; + np->remote_mac[3]=simple_strtol(cur, 0, 16); + cur=delim+1; + if ((delim = strchr(cur, ':')) == NULL) + goto parse_failed; + *delim=0; + np->remote_mac[4]=simple_strtol(cur, 0, 16); + cur=delim+1; + np->remote_mac[5]=simple_strtol(cur, 0, 16); + } + + printk(KERN_INFO "%s: remote ethernet address " + "%02x:%02x:%02x:%02x:%02x:%02x\n", + np->name, + np->remote_mac[0], + np->remote_mac[1], + np->remote_mac[2], + np->remote_mac[3], + np->remote_mac[4], + np->remote_mac[5]); + + return 0; + + parse_failed: + printk(KERN_INFO "%s: couldn't parse config at %s!\n", + np->name, cur); + return -1; +} + +int netpoll_setup(struct netpoll *np) +{ + struct net_device *ndev = NULL; + struct in_device *in_dev; + + if (np->dev_name) + ndev = dev_get_by_name(np->dev_name); + if (!ndev) { + printk(KERN_ERR "%s: %s doesn't exist, aborting.\n", + np->name, np->dev_name); + return -1; + } + if (!ndev->poll_controller) { + printk(KERN_ERR "%s: %s doesn't support polling, aborting.\n", + np->name, np->dev_name); + goto release; + } + + if (!(ndev->flags & IFF_UP)) { + unsigned short oflags; + unsigned long atmost, atleast; + + printk(KERN_INFO "%s: device %s not up yet, forcing it\n", + np->name, np->dev_name); + + oflags = ndev->flags; + + rtnl_shlock(); + if (dev_change_flags(ndev, oflags | IFF_UP) < 0) { + printk(KERN_ERR "%s: failed to open %s\n", + np->name, np->dev_name); + rtnl_shunlock(); + goto release; + } + rtnl_shunlock(); + + atleast = jiffies + HZ/10; + atmost = jiffies + 10*HZ; + while (!netif_carrier_ok(ndev)) { + if (time_after(jiffies, atmost)) { + printk(KERN_NOTICE + "%s: timeout waiting for carrier\n", + np->name); + break; + } + cond_resched(); + } + + if (time_before(jiffies, atleast)) { + printk(KERN_NOTICE "%s: carrier detect appears flaky," + " waiting 10 seconds\n", + np->name); + while (time_before(jiffies, atmost)) + cond_resched(); + } + } + + if (!memcmp(np->local_mac, "\0\0\0\0\0\0", 6) && ndev->dev_addr) + memcpy(np->local_mac, ndev->dev_addr, 6); + + if (!np->local_ip) { + in_dev = in_dev_get(ndev); + + if (!in_dev) { + printk(KERN_ERR "%s: no IP address for %s, aborting\n", + np->name, np->dev_name); + goto release; + } + + np->local_ip = ntohl(in_dev->ifa_list->ifa_local); + in_dev_put(in_dev); + printk(KERN_INFO "%s: local IP %d.%d.%d.%d\n", + np->name, HIPQUAD(np->local_ip)); + } + + np->dev = ndev; + + if(np->rx_hook) { + unsigned long flags; + +#ifdef CONFIG_NETPOLL_RX + np->dev->netpoll_rx = 1; +#endif + + spin_lock_irqsave(&rx_list_lock, flags); + list_add(&np->rx_list, &rx_list); + spin_unlock_irqrestore(&rx_list_lock, flags); + } + + return 0; + release: + dev_put(ndev); + return -1; +} + +void netpoll_cleanup(struct netpoll *np) +{ + if(np->rx_hook) { + unsigned long flags; + + spin_lock_irqsave(&rx_list_lock, flags); + list_del(&np->rx_list); +#ifdef CONFIG_NETPOLL_RX + np->dev->netpoll_rx = 0; +#endif + spin_unlock_irqrestore(&rx_list_lock, flags); + } + + dev_put(np->dev); + np->dev = 0; +} + +int netpoll_trap() +{ + return trapped; +} + +void netpoll_set_trap(int trap) +{ + trapped = trap; +} + +EXPORT_SYMBOL(netpoll_set_trap); +EXPORT_SYMBOL(netpoll_trap); +EXPORT_SYMBOL(netpoll_parse_options); +EXPORT_SYMBOL(netpoll_setup); +EXPORT_SYMBOL(netpoll_cleanup); +EXPORT_SYMBOL(netpoll_send_skb); +EXPORT_SYMBOL(netpoll_send_udp); +EXPORT_SYMBOL(netpoll_poll); diff -Nru a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c --- a/net/ipv4/ip_gre.c Thu Jan 22 18:59:26 2004 +++ b/net/ipv4/ip_gre.c Thu Jan 22 18:59:26 2004 @@ -280,7 +280,7 @@ nt->parms = *parms; if (register_netdevice(dev) < 0) { - kfree(dev); + free_netdev(dev); goto failed; } @@ -1276,7 +1276,7 @@ return err; fail: inet_del_protocol(&ipgre_protocol, IPPROTO_GRE); - kfree(ipgre_fb_tunnel_dev); + free_netdev(ipgre_fb_tunnel_dev); goto out; } diff -Nru a/net/ipv4/ipip.c b/net/ipv4/ipip.c --- a/net/ipv4/ipip.c Thu Jan 22 18:59:27 2004 +++ b/net/ipv4/ipip.c Thu Jan 22 18:59:27 2004 @@ -250,7 +250,7 @@ nt->parms = *parms; if (register_netdevice(dev) < 0) { - kfree(dev); + free_netdev(dev); goto failed; } @@ -899,7 +899,7 @@ return err; fail: xfrm4_tunnel_deregister(&ipip_handler); - kfree(ipip_fb_tunnel_dev); + free_netdev(ipip_fb_tunnel_dev); goto out; } diff -Nru a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c --- a/net/ipv4/ipmr.c Thu Jan 22 18:59:25 2004 +++ b/net/ipv4/ipmr.c Thu Jan 22 18:59:25 2004 @@ -209,7 +209,7 @@ return NULL; if (register_netdevice(dev)) { - kfree(dev); + free_netdev(dev); return NULL; } dev->iflink = 0; diff -Nru a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c --- a/net/ipv6/ip6_tunnel.c Thu Jan 22 18:59:23 2004 +++ b/net/ipv6/ip6_tunnel.c Thu Jan 22 18:59:23 2004 @@ -245,7 +245,7 @@ t->parms = *p; if ((err = register_netdevice(dev)) < 0) { - kfree(dev); + free_netdev(dev); return err; } dev_hold(dev); @@ -1118,7 +1118,7 @@ ip6ip6_fb_tnl_dev->init = ip6ip6_fb_tnl_dev_init; if ((err = register_netdev(ip6ip6_fb_tnl_dev))) { - kfree(ip6ip6_fb_tnl_dev); + free_netdev(ip6ip6_fb_tnl_dev); goto fail; } return 0; diff -Nru a/net/ipv6/sit.c b/net/ipv6/sit.c --- a/net/ipv6/sit.c Thu Jan 22 18:59:26 2004 +++ b/net/ipv6/sit.c Thu Jan 22 18:59:26 2004 @@ -187,7 +187,7 @@ nt->parms = *parms; if (register_netdevice(dev) < 0) { - kfree(dev); + free_netdev(dev); goto failed; } @@ -840,6 +840,6 @@ return err; fail: inet_del_protocol(&sit_protocol, IPPROTO_IPV6); - kfree(ipip6_fb_tunnel_dev); + free_netdev(ipip6_fb_tunnel_dev); goto out; } diff -Nru a/net/irda/irlan/irlan_common.c b/net/irda/irlan/irlan_common.c --- a/net/irda/irlan/irlan_common.c Thu Jan 22 18:59:25 2004 +++ b/net/irda/irlan/irlan_common.c Thu Jan 22 18:59:25 2004 @@ -224,7 +224,7 @@ IRDA_DEBUG(2, "%s(), register_netdev() failed!\n", __FUNCTION__ ); self = NULL; - kfree(dev); + free_netdev(dev); } else { rtnl_lock(); list_add_rcu(&self->dev_list, &irlans); diff -Nru a/net/irda/irlan/irlan_eth.c b/net/irda/irlan/irlan_eth.c --- a/net/irda/irlan/irlan_eth.c Thu Jan 22 18:59:24 2004 +++ b/net/irda/irlan/irlan_eth.c Thu Jan 22 18:59:24 2004 @@ -60,7 +60,7 @@ dev->hard_start_xmit = irlan_eth_xmit; dev->get_stats = irlan_eth_get_stats; dev->set_multicast_list = irlan_eth_set_multicast_list; - dev->destructor = (void (*)(struct net_device *)) kfree; + dev->destructor = free_netdev; SET_MODULE_OWNER(dev); diff -Nru a/net/lapb/lapb_iface.c b/net/lapb/lapb_iface.c --- a/net/lapb/lapb_iface.c Thu Jan 22 18:59:25 2004 +++ b/net/lapb/lapb_iface.c Thu Jan 22 18:59:25 2004 @@ -81,18 +81,14 @@ lapb_hold(lapb); } -/* - * Convert the integer token used by the device driver into a pointer - * to a LAPB control structure. - */ -static struct lapb_cb *__lapb_tokentostruct(void *token) +static struct lapb_cb *__lapb_devtostruct(struct net_device *dev) { struct list_head *entry; struct lapb_cb *lapb, *use = NULL; list_for_each(entry, &lapb_list) { lapb = list_entry(entry, struct lapb_cb, node); - if (lapb->token == token) { + if (lapb->dev == dev) { use = lapb; break; } @@ -104,12 +100,12 @@ return use; } -static struct lapb_cb *lapb_tokentostruct(void *token) +static struct lapb_cb *lapb_devtostruct(struct net_device *dev) { struct lapb_cb *rc; read_lock_bh(&lapb_list_lock); - rc = __lapb_tokentostruct(token); + rc = __lapb_devtostruct(dev); read_unlock_bh(&lapb_list_lock); return rc; @@ -144,14 +140,14 @@ return lapb; } -int lapb_register(void *token, struct lapb_register_struct *callbacks) +int lapb_register(struct net_device *dev, struct lapb_register_struct *callbacks) { struct lapb_cb *lapb; int rc = LAPB_BADTOKEN; write_lock_bh(&lapb_list_lock); - lapb = __lapb_tokentostruct(token); + lapb = __lapb_devtostruct(dev); if (lapb) { lapb_put(lapb); goto out; @@ -162,7 +158,7 @@ if (!lapb) goto out; - lapb->token = token; + lapb->dev = dev; lapb->callbacks = *callbacks; __lapb_insert_cb(lapb); @@ -175,13 +171,13 @@ return rc; } -int lapb_unregister(void *token) +int lapb_unregister(struct net_device *dev) { struct lapb_cb *lapb; int rc = LAPB_BADTOKEN; write_unlock_bh(&lapb_list_lock); - lapb = __lapb_tokentostruct(token); + lapb = __lapb_devtostruct(dev); if (!lapb) goto out; @@ -199,10 +195,10 @@ return rc; } -int lapb_getparms(void *token, struct lapb_parms_struct *parms) +int lapb_getparms(struct net_device *dev, struct lapb_parms_struct *parms) { int rc = LAPB_BADTOKEN; - struct lapb_cb *lapb = lapb_tokentostruct(token); + struct lapb_cb *lapb = lapb_devtostruct(dev); if (!lapb) goto out; @@ -231,10 +227,10 @@ return rc; } -int lapb_setparms(void *token, struct lapb_parms_struct *parms) +int lapb_setparms(struct net_device *dev, struct lapb_parms_struct *parms) { int rc = LAPB_BADTOKEN; - struct lapb_cb *lapb = lapb_tokentostruct(token); + struct lapb_cb *lapb = lapb_devtostruct(dev); if (!lapb) goto out; @@ -264,9 +260,9 @@ return rc; } -int lapb_connect_request(void *token) +int lapb_connect_request(struct net_device *dev) { - struct lapb_cb *lapb = lapb_tokentostruct(token); + struct lapb_cb *lapb = lapb_devtostruct(dev); int rc = LAPB_BADTOKEN; if (!lapb) @@ -283,7 +279,7 @@ lapb_establish_data_link(lapb); #if LAPB_DEBUG > 0 - printk(KERN_DEBUG "lapb: (%p) S0 -> S1\n", lapb->token); + printk(KERN_DEBUG "lapb: (%p) S0 -> S1\n", lapb->dev); #endif lapb->state = LAPB_STATE_1; @@ -294,9 +290,9 @@ return rc; } -int lapb_disconnect_request(void *token) +int lapb_disconnect_request(struct net_device *dev) { - struct lapb_cb *lapb = lapb_tokentostruct(token); + struct lapb_cb *lapb = lapb_devtostruct(dev); int rc = LAPB_BADTOKEN; if (!lapb) @@ -309,10 +305,10 @@ case LAPB_STATE_1: #if LAPB_DEBUG > 1 - printk(KERN_DEBUG "lapb: (%p) S1 TX DISC(1)\n", lapb->token); + printk(KERN_DEBUG "lapb: (%p) S1 TX DISC(1)\n", lapb->dev); #endif #if LAPB_DEBUG > 0 - printk(KERN_DEBUG "lapb: (%p) S1 -> S0\n", lapb->token); + printk(KERN_DEBUG "lapb: (%p) S1 -> S0\n", lapb->dev); #endif lapb_send_control(lapb, LAPB_DISC, LAPB_POLLON, LAPB_COMMAND); lapb->state = LAPB_STATE_0; @@ -333,10 +329,10 @@ lapb->state = LAPB_STATE_2; #if LAPB_DEBUG > 1 - printk(KERN_DEBUG "lapb: (%p) S3 DISC(1)\n", lapb->token); + printk(KERN_DEBUG "lapb: (%p) S3 DISC(1)\n", lapb->dev); #endif #if LAPB_DEBUG > 0 - printk(KERN_DEBUG "lapb: (%p) S3 -> S2\n", lapb->token); + printk(KERN_DEBUG "lapb: (%p) S3 -> S2\n", lapb->dev); #endif rc = LAPB_OK; @@ -346,9 +342,9 @@ return rc; } -int lapb_data_request(void *token, struct sk_buff *skb) +int lapb_data_request(struct net_device *dev, struct sk_buff *skb) { - struct lapb_cb *lapb = lapb_tokentostruct(token); + struct lapb_cb *lapb = lapb_devtostruct(dev); int rc = LAPB_BADTOKEN; if (!lapb) @@ -367,9 +363,9 @@ return rc; } -int lapb_data_received(void *token, struct sk_buff *skb) +int lapb_data_received(struct net_device *dev, struct sk_buff *skb) { - struct lapb_cb *lapb = lapb_tokentostruct(token); + struct lapb_cb *lapb = lapb_devtostruct(dev); int rc = LAPB_BADTOKEN; if (lapb) { @@ -384,31 +380,31 @@ void lapb_connect_confirmation(struct lapb_cb *lapb, int reason) { if (lapb->callbacks.connect_confirmation) - lapb->callbacks.connect_confirmation(lapb->token, reason); + lapb->callbacks.connect_confirmation(lapb->dev, reason); } void lapb_connect_indication(struct lapb_cb *lapb, int reason) { if (lapb->callbacks.connect_indication) - lapb->callbacks.connect_indication(lapb->token, reason); + lapb->callbacks.connect_indication(lapb->dev, reason); } void lapb_disconnect_confirmation(struct lapb_cb *lapb, int reason) { if (lapb->callbacks.disconnect_confirmation) - lapb->callbacks.disconnect_confirmation(lapb->token, reason); + lapb->callbacks.disconnect_confirmation(lapb->dev, reason); } void lapb_disconnect_indication(struct lapb_cb *lapb, int reason) { if (lapb->callbacks.disconnect_indication) - lapb->callbacks.disconnect_indication(lapb->token, reason); + lapb->callbacks.disconnect_indication(lapb->dev, reason); } int lapb_data_indication(struct lapb_cb *lapb, struct sk_buff *skb) { if (lapb->callbacks.data_indication) - return lapb->callbacks.data_indication(lapb->token, skb); + return lapb->callbacks.data_indication(lapb->dev, skb); kfree_skb(skb); return NET_RX_CN_HIGH; /* For now; must be != NET_RX_DROP */ @@ -419,7 +415,7 @@ int used = 0; if (lapb->callbacks.data_transmit) { - lapb->callbacks.data_transmit(lapb->token, skb); + lapb->callbacks.data_transmit(lapb->dev, skb); used = 1; } diff -Nru a/net/lapb/lapb_in.c b/net/lapb/lapb_in.c --- a/net/lapb/lapb_in.c Thu Jan 22 18:59:25 2004 +++ b/net/lapb/lapb_in.c Thu Jan 22 18:59:25 2004 @@ -47,23 +47,23 @@ case LAPB_SABM: #if LAPB_DEBUG > 1 printk(KERN_DEBUG "lapb: (%p) S0 RX SABM(%d)\n", - lapb->token, frame->pf); + lapb->dev, frame->pf); #endif if (lapb->mode & LAPB_EXTENDED) { #if LAPB_DEBUG > 1 printk(KERN_DEBUG "lapb: (%p) S0 TX DM(%d)\n", - lapb->token, frame->pf); + lapb->dev, frame->pf); #endif lapb_send_control(lapb, LAPB_DM, frame->pf, LAPB_RESPONSE); } else { #if LAPB_DEBUG > 1 printk(KERN_DEBUG "lapb: (%p) S0 TX UA(%d)\n", - lapb->token, frame->pf); + lapb->dev, frame->pf); #endif #if LAPB_DEBUG > 0 printk(KERN_DEBUG "lapb: (%p) S0 -> S3\n", - lapb->token); + lapb->dev); #endif lapb_send_control(lapb, LAPB_UA, frame->pf, LAPB_RESPONSE); @@ -82,16 +82,16 @@ case LAPB_SABME: #if LAPB_DEBUG > 1 printk(KERN_DEBUG "lapb: (%p) S0 RX SABME(%d)\n", - lapb->token, frame->pf); + lapb->dev, frame->pf); #endif if (lapb->mode & LAPB_EXTENDED) { #if LAPB_DEBUG > 1 printk(KERN_DEBUG "lapb: (%p) S0 TX UA(%d)\n", - lapb->token, frame->pf); + lapb->dev, frame->pf); #endif #if LAPB_DEBUG > 0 printk(KERN_DEBUG "lapb: (%p) S0 -> S3\n", - lapb->token); + lapb->dev); #endif lapb_send_control(lapb, LAPB_UA, frame->pf, LAPB_RESPONSE); @@ -107,7 +107,7 @@ } else { #if LAPB_DEBUG > 1 printk(KERN_DEBUG "lapb: (%p) S0 TX DM(%d)\n", - lapb->token, frame->pf); + lapb->dev, frame->pf); #endif lapb_send_control(lapb, LAPB_DM, frame->pf, LAPB_RESPONSE); @@ -117,9 +117,9 @@ case LAPB_DISC: #if LAPB_DEBUG > 1 printk(KERN_DEBUG "lapb: (%p) S0 RX DISC(%d)\n", - lapb->token, frame->pf); + lapb->dev, frame->pf); printk(KERN_DEBUG "lapb: (%p) S0 TX UA(%d)\n", - lapb->token, frame->pf); + lapb->dev, frame->pf); #endif lapb_send_control(lapb, LAPB_UA, frame->pf, LAPB_RESPONSE); @@ -143,19 +143,19 @@ case LAPB_SABM: #if LAPB_DEBUG > 1 printk(KERN_DEBUG "lapb: (%p) S1 RX SABM(%d)\n", - lapb->token, frame->pf); + lapb->dev, frame->pf); #endif if (lapb->mode & LAPB_EXTENDED) { #if LAPB_DEBUG > 1 printk(KERN_DEBUG "lapb: (%p) S1 TX DM(%d)\n", - lapb->token, frame->pf); + lapb->dev, frame->pf); #endif lapb_send_control(lapb, LAPB_DM, frame->pf, LAPB_RESPONSE); } else { #if LAPB_DEBUG > 1 printk(KERN_DEBUG "lapb: (%p) S1 TX UA(%d)\n", - lapb->token, frame->pf); + lapb->dev, frame->pf); #endif lapb_send_control(lapb, LAPB_UA, frame->pf, LAPB_RESPONSE); @@ -165,19 +165,19 @@ case LAPB_SABME: #if LAPB_DEBUG > 1 printk(KERN_DEBUG "lapb: (%p) S1 RX SABME(%d)\n", - lapb->token, frame->pf); + lapb->dev, frame->pf); #endif if (lapb->mode & LAPB_EXTENDED) { #if LAPB_DEBUG > 1 printk(KERN_DEBUG "lapb: (%p) S1 TX UA(%d)\n", - lapb->token, frame->pf); + lapb->dev, frame->pf); #endif lapb_send_control(lapb, LAPB_UA, frame->pf, LAPB_RESPONSE); } else { #if LAPB_DEBUG > 1 printk(KERN_DEBUG "lapb: (%p) S1 TX DM(%d)\n", - lapb->token, frame->pf); + lapb->dev, frame->pf); #endif lapb_send_control(lapb, LAPB_DM, frame->pf, LAPB_RESPONSE); @@ -187,9 +187,9 @@ case LAPB_DISC: #if LAPB_DEBUG > 1 printk(KERN_DEBUG "lapb: (%p) S1 RX DISC(%d)\n", - lapb->token, frame->pf); + lapb->dev, frame->pf); printk(KERN_DEBUG "lapb: (%p) S1 TX DM(%d)\n", - lapb->token, frame->pf); + lapb->dev, frame->pf); #endif lapb_send_control(lapb, LAPB_DM, frame->pf, LAPB_RESPONSE); @@ -198,12 +198,12 @@ case LAPB_UA: #if LAPB_DEBUG > 1 printk(KERN_DEBUG "lapb: (%p) S1 RX UA(%d)\n", - lapb->token, frame->pf); + lapb->dev, frame->pf); #endif if (frame->pf) { #if LAPB_DEBUG > 0 printk(KERN_DEBUG "lapb: (%p) S1 -> S3\n", - lapb->token); + lapb->dev); #endif lapb_stop_t1timer(lapb); lapb_stop_t2timer(lapb); @@ -220,12 +220,12 @@ case LAPB_DM: #if LAPB_DEBUG > 1 printk(KERN_DEBUG "lapb: (%p) S1 RX DM(%d)\n", - lapb->token, frame->pf); + lapb->dev, frame->pf); #endif if (frame->pf) { #if LAPB_DEBUG > 0 printk(KERN_DEBUG "lapb: (%p) S1 -> S0\n", - lapb->token); + lapb->dev); #endif lapb_clear_queues(lapb); lapb->state = LAPB_STATE_0; @@ -251,9 +251,9 @@ case LAPB_SABME: #if LAPB_DEBUG > 1 printk(KERN_DEBUG "lapb: (%p) S2 RX {SABM,SABME}(%d)\n", - lapb->token, frame->pf); + lapb->dev, frame->pf); printk(KERN_DEBUG "lapb: (%p) S2 TX DM(%d)\n", - lapb->token, frame->pf); + lapb->dev, frame->pf); #endif lapb_send_control(lapb, LAPB_DM, frame->pf, LAPB_RESPONSE); @@ -262,9 +262,9 @@ case LAPB_DISC: #if LAPB_DEBUG > 1 printk(KERN_DEBUG "lapb: (%p) S2 RX DISC(%d)\n", - lapb->token, frame->pf); + lapb->dev, frame->pf); printk(KERN_DEBUG "lapb: (%p) S2 TX UA(%d)\n", - lapb->token, frame->pf); + lapb->dev, frame->pf); #endif lapb_send_control(lapb, LAPB_UA, frame->pf, LAPB_RESPONSE); @@ -273,12 +273,12 @@ case LAPB_UA: #if LAPB_DEBUG > 1 printk(KERN_DEBUG "lapb: (%p) S2 RX UA(%d)\n", - lapb->token, frame->pf); + lapb->dev, frame->pf); #endif if (frame->pf) { #if LAPB_DEBUG > 0 printk(KERN_DEBUG "lapb: (%p) S2 -> S0\n", - lapb->token); + lapb->dev); #endif lapb->state = LAPB_STATE_0; lapb_start_t1timer(lapb); @@ -290,12 +290,12 @@ case LAPB_DM: #if LAPB_DEBUG > 1 printk(KERN_DEBUG "lapb: (%p) S2 RX DM(%d)\n", - lapb->token, frame->pf); + lapb->dev, frame->pf); #endif if (frame->pf) { #if LAPB_DEBUG > 0 printk(KERN_DEBUG "lapb: (%p) S2 -> S0\n", - lapb->token); + lapb->dev); #endif lapb->state = LAPB_STATE_0; lapb_start_t1timer(lapb); @@ -311,9 +311,9 @@ case LAPB_RR: #if LAPB_DEBUG > 1 printk(KERN_DEBUG "lapb: (%p) S2 RX {I,REJ,RNR,RR}" - "(%d)\n", lapb->token, frame->pf); + "(%d)\n", lapb->dev, frame->pf); printk(KERN_DEBUG "lapb: (%p) S2 RX DM(%d)\n", - lapb->token, frame->pf); + lapb->dev, frame->pf); #endif if (frame->pf) lapb_send_control(lapb, LAPB_DM, frame->pf, @@ -339,19 +339,19 @@ case LAPB_SABM: #if LAPB_DEBUG > 1 printk(KERN_DEBUG "lapb: (%p) S3 RX SABM(%d)\n", - lapb->token, frame->pf); + lapb->dev, frame->pf); #endif if (lapb->mode & LAPB_EXTENDED) { #if LAPB_DEBUG > 1 printk(KERN_DEBUG "lapb: (%p) S3 TX DM(%d)\n", - lapb->token, frame->pf); + lapb->dev, frame->pf); #endif lapb_send_control(lapb, LAPB_DM, frame->pf, LAPB_RESPONSE); } else { #if LAPB_DEBUG > 1 printk(KERN_DEBUG "lapb: (%p) S3 TX UA(%d)\n", - lapb->token, frame->pf); + lapb->dev, frame->pf); #endif lapb_send_control(lapb, LAPB_UA, frame->pf, LAPB_RESPONSE); @@ -369,12 +369,12 @@ case LAPB_SABME: #if LAPB_DEBUG > 1 printk(KERN_DEBUG "lapb: (%p) S3 RX SABME(%d)\n", - lapb->token, frame->pf); + lapb->dev, frame->pf); #endif if (lapb->mode & LAPB_EXTENDED) { #if LAPB_DEBUG > 1 printk(KERN_DEBUG "lapb: (%p) S3 TX UA(%d)\n", - lapb->token, frame->pf); + lapb->dev, frame->pf); #endif lapb_send_control(lapb, LAPB_UA, frame->pf, LAPB_RESPONSE); @@ -389,7 +389,7 @@ } else { #if LAPB_DEBUG > 1 printk(KERN_DEBUG "lapb: (%p) S3 TX DM(%d)\n", - lapb->token, frame->pf); + lapb->dev, frame->pf); #endif lapb_send_control(lapb, LAPB_DM, frame->pf, LAPB_RESPONSE); @@ -399,11 +399,11 @@ case LAPB_DISC: #if LAPB_DEBUG > 1 printk(KERN_DEBUG "lapb: (%p) S3 RX DISC(%d)\n", - lapb->token, frame->pf); + lapb->dev, frame->pf); #endif #if LAPB_DEBUG > 0 printk(KERN_DEBUG "lapb: (%p) S3 -> S0\n", - lapb->token); + lapb->dev); #endif lapb_clear_queues(lapb); lapb_send_control(lapb, LAPB_UA, frame->pf, @@ -417,11 +417,11 @@ case LAPB_DM: #if LAPB_DEBUG > 1 printk(KERN_DEBUG "lapb: (%p) S3 RX DM(%d)\n", - lapb->token, frame->pf); + lapb->dev, frame->pf); #endif #if LAPB_DEBUG > 0 printk(KERN_DEBUG "lapb: (%p) S3 -> S0\n", - lapb->token); + lapb->dev); #endif lapb_clear_queues(lapb); lapb->state = LAPB_STATE_0; @@ -433,7 +433,7 @@ case LAPB_RNR: #if LAPB_DEBUG > 1 printk(KERN_DEBUG "lapb: (%p) S3 RX RNR(%d) R%d\n", - lapb->token, frame->pf, frame->nr); + lapb->dev, frame->pf, frame->nr); #endif lapb->condition |= LAPB_PEER_RX_BUSY_CONDITION; lapb_check_need_response(lapb, frame->cr, frame->pf); @@ -445,7 +445,7 @@ lapb_transmit_frmr(lapb); #if LAPB_DEBUG > 0 printk(KERN_DEBUG "lapb: (%p) S3 -> S4\n", - lapb->token); + lapb->dev); #endif lapb_start_t1timer(lapb); lapb_stop_t2timer(lapb); @@ -457,7 +457,7 @@ case LAPB_RR: #if LAPB_DEBUG > 1 printk(KERN_DEBUG "lapb: (%p) S3 RX RR(%d) R%d\n", - lapb->token, frame->pf, frame->nr); + lapb->dev, frame->pf, frame->nr); #endif lapb->condition &= ~LAPB_PEER_RX_BUSY_CONDITION; lapb_check_need_response(lapb, frame->cr, frame->pf); @@ -469,7 +469,7 @@ lapb_transmit_frmr(lapb); #if LAPB_DEBUG > 0 printk(KERN_DEBUG "lapb: (%p) S3 -> S4\n", - lapb->token); + lapb->dev); #endif lapb_start_t1timer(lapb); lapb_stop_t2timer(lapb); @@ -481,7 +481,7 @@ case LAPB_REJ: #if LAPB_DEBUG > 1 printk(KERN_DEBUG "lapb: (%p) S3 RX REJ(%d) R%d\n", - lapb->token, frame->pf, frame->nr); + lapb->dev, frame->pf, frame->nr); #endif lapb->condition &= ~LAPB_PEER_RX_BUSY_CONDITION; lapb_check_need_response(lapb, frame->cr, frame->pf); @@ -496,7 +496,7 @@ lapb_transmit_frmr(lapb); #if LAPB_DEBUG > 0 printk(KERN_DEBUG "lapb: (%p) S3 -> S4\n", - lapb->token); + lapb->dev); #endif lapb_start_t1timer(lapb); lapb_stop_t2timer(lapb); @@ -508,7 +508,7 @@ case LAPB_I: #if LAPB_DEBUG > 1 printk(KERN_DEBUG "lapb: (%p) S3 RX I(%d) S%d R%d\n", - lapb->token, frame->pf, frame->ns, frame->nr); + lapb->dev, frame->pf, frame->ns, frame->nr); #endif if (!lapb_validate_nr(lapb, frame->nr)) { lapb->frmr_data = *frame; @@ -516,7 +516,7 @@ lapb_transmit_frmr(lapb); #if LAPB_DEBUG > 0 printk(KERN_DEBUG "lapb: (%p) S3 -> S4\n", - lapb->token); + lapb->dev); #endif lapb_start_t1timer(lapb); lapb_stop_t2timer(lapb); @@ -564,7 +564,7 @@ #if LAPB_DEBUG > 1 printk(KERN_DEBUG "lapb: (%p) S3 TX REJ(%d) R%d\n", - lapb->token, frame->pf, lapb->vr); + lapb->dev, frame->pf, lapb->vr); #endif lapb->condition |= LAPB_REJECT_CONDITION; lapb_send_control(lapb, LAPB_REJ, @@ -578,14 +578,14 @@ case LAPB_FRMR: #if LAPB_DEBUG > 1 printk(KERN_DEBUG "lapb: (%p) S3 RX FRMR(%d) %02X " - "%02X %02X %02X %02X\n", lapb->token, frame->pf, + "%02X %02X %02X %02X\n", lapb->dev, frame->pf, skb->data[0], skb->data[1], skb->data[2], skb->data[3], skb->data[4]); #endif lapb_establish_data_link(lapb); #if LAPB_DEBUG > 0 printk(KERN_DEBUG "lapb: (%p) S3 -> S1\n", - lapb->token); + lapb->dev); #endif lapb_requeue_frames(lapb); lapb->state = LAPB_STATE_1; @@ -594,13 +594,13 @@ case LAPB_ILLEGAL: #if LAPB_DEBUG > 1 printk(KERN_DEBUG "lapb: (%p) S3 RX ILLEGAL(%d)\n", - lapb->token, frame->pf); + lapb->dev, frame->pf); #endif lapb->frmr_data = *frame; lapb->frmr_type = LAPB_FRMR_W; lapb_transmit_frmr(lapb); #if LAPB_DEBUG > 0 - printk(KERN_DEBUG "lapb: (%p) S3 -> S4\n", lapb->token); + printk(KERN_DEBUG "lapb: (%p) S3 -> S4\n", lapb->dev); #endif lapb_start_t1timer(lapb); lapb_stop_t2timer(lapb); @@ -624,23 +624,23 @@ case LAPB_SABM: #if LAPB_DEBUG > 1 printk(KERN_DEBUG "lapb: (%p) S4 RX SABM(%d)\n", - lapb->token, frame->pf); + lapb->dev, frame->pf); #endif if (lapb->mode & LAPB_EXTENDED) { #if LAPB_DEBUG > 1 printk(KERN_DEBUG "lapb: (%p) S4 TX DM(%d)\n", - lapb->token, frame->pf); + lapb->dev, frame->pf); #endif lapb_send_control(lapb, LAPB_DM, frame->pf, LAPB_RESPONSE); } else { #if LAPB_DEBUG > 1 printk(KERN_DEBUG "lapb: (%p) S4 TX UA(%d)\n", - lapb->token, frame->pf); + lapb->dev, frame->pf); #endif #if LAPB_DEBUG > 0 printk(KERN_DEBUG "lapb: (%p) S4 -> S3\n", - lapb->token); + lapb->dev); #endif lapb_send_control(lapb, LAPB_UA, frame->pf, LAPB_RESPONSE); @@ -659,16 +659,16 @@ case LAPB_SABME: #if LAPB_DEBUG > 1 printk(KERN_DEBUG "lapb: (%p) S4 RX SABME(%d)\n", - lapb->token, frame->pf); + lapb->dev, frame->pf); #endif if (lapb->mode & LAPB_EXTENDED) { #if LAPB_DEBUG > 1 printk(KERN_DEBUG "lapb: (%p) S4 TX UA(%d)\n", - lapb->token, frame->pf); + lapb->dev, frame->pf); #endif #if LAPB_DEBUG > 0 printk(KERN_DEBUG "lapb: (%p) S4 -> S3\n", - lapb->token); + lapb->dev); #endif lapb_send_control(lapb, LAPB_UA, frame->pf, LAPB_RESPONSE); @@ -684,7 +684,7 @@ } else { #if LAPB_DEBUG > 1 printk(KERN_DEBUG "lapb: (%p) S4 TX DM(%d)\n", - lapb->token, frame->pf); + lapb->dev, frame->pf); #endif lapb_send_control(lapb, LAPB_DM, frame->pf, LAPB_RESPONSE); diff -Nru a/net/lapb/lapb_out.c b/net/lapb/lapb_out.c --- a/net/lapb/lapb_out.c Thu Jan 22 18:59:26 2004 +++ b/net/lapb/lapb_out.c Thu Jan 22 18:59:26 2004 @@ -63,7 +63,7 @@ #if LAPB_DEBUG > 1 printk(KERN_DEBUG "lapb: (%p) S%d TX I(%d) S%d R%d\n", - lapb->token, lapb->state, poll_bit, lapb->vs, lapb->vr); + lapb->dev, lapb->state, poll_bit, lapb->vs, lapb->vr); #endif lapb_transmit_buffer(lapb, skb, LAPB_COMMAND); @@ -151,7 +151,7 @@ #if LAPB_DEBUG > 2 printk(KERN_DEBUG "lapb: (%p) S%d TX %02X %02X %02X\n", - lapb->token, lapb->state, + lapb->dev, lapb->state, skb->data[0], skb->data[1], skb->data[2]); #endif @@ -167,13 +167,13 @@ if (lapb->mode & LAPB_EXTENDED) { #if LAPB_DEBUG > 1 printk(KERN_DEBUG "lapb: (%p) S%d TX SABME(1)\n", - lapb->token, lapb->state); + lapb->dev, lapb->state); #endif lapb_send_control(lapb, LAPB_SABME, LAPB_POLLON, LAPB_COMMAND); } else { #if LAPB_DEBUG > 1 printk(KERN_DEBUG "lapb: (%p) S%d TX SABM(1)\n", - lapb->token, lapb->state); + lapb->dev, lapb->state); #endif lapb_send_control(lapb, LAPB_SABM, LAPB_POLLON, LAPB_COMMAND); } @@ -186,7 +186,7 @@ { #if LAPB_DEBUG > 1 printk(KERN_DEBUG "lapb: (%p) S%d TX RR(1) R%d\n", - lapb->token, lapb->state, lapb->vr); + lapb->dev, lapb->state, lapb->vr); #endif lapb_send_control(lapb, LAPB_RR, LAPB_POLLON, LAPB_RESPONSE); @@ -198,7 +198,7 @@ { #if LAPB_DEBUG > 1 printk(KERN_DEBUG "lapb: (%p) S%d TX RR(0) R%d\n", - lapb->token, lapb->state, lapb->vr); + lapb->dev, lapb->state, lapb->vr); #endif lapb_send_control(lapb, LAPB_RR, LAPB_POLLOFF, LAPB_RESPONSE); diff -Nru a/net/lapb/lapb_subr.c b/net/lapb/lapb_subr.c --- a/net/lapb/lapb_subr.c Thu Jan 22 18:59:24 2004 +++ b/net/lapb/lapb_subr.c Thu Jan 22 18:59:24 2004 @@ -114,7 +114,7 @@ #if LAPB_DEBUG > 2 printk(KERN_DEBUG "lapb: (%p) S%d RX %02X %02X %02X\n", - lapb->token, lapb->state, + lapb->dev, lapb->state, skb->data[0], skb->data[1], skb->data[2]); #endif @@ -287,7 +287,7 @@ #if LAPB_DEBUG > 1 printk(KERN_DEBUG "lapb: (%p) S%d TX FRMR %02X %02X %02X %02X %02X\n", - lapb->token, lapb->state, + lapb->dev, lapb->state, skb->data[1], skb->data[2], skb->data[3], skb->data[4], skb->data[5]); #endif @@ -304,7 +304,7 @@ #if LAPB_DEBUG > 1 printk(KERN_DEBUG "lapb: (%p) S%d TX FRMR %02X %02X %02X\n", - lapb->token, lapb->state, skb->data[1], + lapb->dev, lapb->state, skb->data[1], skb->data[2], skb->data[3]); #endif } diff -Nru a/net/lapb/lapb_timer.c b/net/lapb/lapb_timer.c --- a/net/lapb/lapb_timer.c Thu Jan 22 18:59:24 2004 +++ b/net/lapb/lapb_timer.c Thu Jan 22 18:59:24 2004 @@ -107,19 +107,19 @@ lapb->state = LAPB_STATE_0; lapb_disconnect_indication(lapb, LAPB_TIMEDOUT); #if LAPB_DEBUG > 0 - printk(KERN_DEBUG "lapb: (%p) S1 -> S0\n", lapb->token); + printk(KERN_DEBUG "lapb: (%p) S1 -> S0\n", lapb->dev); #endif return; } else { lapb->n2count++; if (lapb->mode & LAPB_EXTENDED) { #if LAPB_DEBUG > 1 - printk(KERN_DEBUG "lapb: (%p) S1 TX SABME(1)\n", lapb->token); + printk(KERN_DEBUG "lapb: (%p) S1 TX SABME(1)\n", lapb->dev); #endif lapb_send_control(lapb, LAPB_SABME, LAPB_POLLON, LAPB_COMMAND); } else { #if LAPB_DEBUG > 1 - printk(KERN_DEBUG "lapb: (%p) S1 TX SABM(1)\n", lapb->token); + printk(KERN_DEBUG "lapb: (%p) S1 TX SABM(1)\n", lapb->dev); #endif lapb_send_control(lapb, LAPB_SABM, LAPB_POLLON, LAPB_COMMAND); } @@ -135,13 +135,13 @@ lapb->state = LAPB_STATE_0; lapb_disconnect_confirmation(lapb, LAPB_TIMEDOUT); #if LAPB_DEBUG > 0 - printk(KERN_DEBUG "lapb: (%p) S2 -> S0\n", lapb->token); + printk(KERN_DEBUG "lapb: (%p) S2 -> S0\n", lapb->dev); #endif return; } else { lapb->n2count++; #if LAPB_DEBUG > 1 - printk(KERN_DEBUG "lapb: (%p) S2 TX DISC(1)\n", lapb->token); + printk(KERN_DEBUG "lapb: (%p) S2 TX DISC(1)\n", lapb->dev); #endif lapb_send_control(lapb, LAPB_DISC, LAPB_POLLON, LAPB_COMMAND); } @@ -157,7 +157,7 @@ lapb_stop_t2timer(lapb); lapb_disconnect_indication(lapb, LAPB_TIMEDOUT); #if LAPB_DEBUG > 0 - printk(KERN_DEBUG "lapb: (%p) S3 -> S0\n", lapb->token); + printk(KERN_DEBUG "lapb: (%p) S3 -> S0\n", lapb->dev); #endif return; } else { @@ -175,7 +175,7 @@ lapb->state = LAPB_STATE_0; lapb_disconnect_indication(lapb, LAPB_TIMEDOUT); #if LAPB_DEBUG > 0 - printk(KERN_DEBUG "lapb: (%p) S4 -> S0\n", lapb->token); + printk(KERN_DEBUG "lapb: (%p) S4 -> S0\n", lapb->dev); #endif return; } else { diff -Nru a/net/wanrouter/wanmain.c b/net/wanrouter/wanmain.c --- a/net/wanrouter/wanmain.c Thu Jan 22 18:59:26 2004 +++ b/net/wanrouter/wanmain.c Thu Jan 22 18:59:26 2004 @@ -726,8 +726,6 @@ if (dev->name == NULL) { err = -EINVAL; - } else if (dev_get(dev->name)) { - err = -EEXIST; /* name already exists */ } else { #ifdef WANDEBUG