diff options
| author | Linus Torvalds <torvalds@home.osdl.org> | 2004-02-06 03:16:12 -0800 |
|---|---|---|
| committer | Linus Torvalds <torvalds@home.osdl.org> | 2004-02-06 03:16:12 -0800 |
| commit | 0bd56a0a6e716d12b914226ebccf2d997c021b3e (patch) | |
| tree | 4839e8b03fce4588c42cb06dde715afa409cb663 | |
| parent | 774bf41565f413587099ae1240c1eb9159face77 (diff) | |
| parent | ec041cd9f5840519d117e08a0ee0092a960bce42 (diff) | |
Merge bk://gkernel.bkbits.net/net-drivers-2.5
into home.osdl.org:/home/torvalds/v2.5/linux
96 files changed, 5274 insertions, 6105 deletions
diff --git a/Documentation/networking/bonding.txt b/Documentation/networking/bonding.txt index 32acbb0020f4..372b6f5c181b 100644 --- a/Documentation/networking/bonding.txt +++ b/Documentation/networking/bonding.txt @@ -21,7 +21,7 @@ userspace tools, please follow the links at the end of this file. Table of Contents ================= - + Installation Bond Configuration Module Parameters @@ -66,7 +66,7 @@ of the -I option on the ifenslave compile line is to make sure it uses /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 @@ Bond Configuration ================== 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 @@ bonding interface (bond1), use MASTER=bond1 in the config file to make the 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 @@ manually configure the bonding device with the following commands: (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 @@ functions such as Interface_Scan_Next will report that association. 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 @@ parameters be specified, otherwise serious network degradation will occur 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 @@ arp_ip_target 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 @@ max_bonds 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 @@ mode 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 @@ mode 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 @@ mode 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 @@ mode 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 @@ mode 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 @@ mode 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 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 @@ Verifying Bond Configuration ---------------------------- 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 @@ parameters of mode=0 and miimon=1000 is shown below. 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 @@ Frequently Asked Questions 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 @@ Frequently Asked Questions 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 @@ Frequently Asked Questions 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 @@ Frequently Asked Questions 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 @@ Frequently Asked Questions 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 @@ High Availability ================= 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 @@ Or, put the following lines in /etc/modules.conf: 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 @@ Example 2 : host to switch at twice the speed # 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 @@ by another external mechanism, it is good to have host1's active interface 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 @@ The main limitations are : 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 @@ Donald Becker's Ethernet Drivers and diag programs may be found at : 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 --git a/Documentation/networking/ifenslave.c b/Documentation/networking/ifenslave.c index a4b44dffb877..b88d62552073 100644 --- a/Documentation/networking/ifenslave.c +++ b/Documentation/networking/ifenslave.c @@ -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 <N>] > ... - * * Author: Donald Becker <becker@cesdis.gsfc.nasa.gov> * 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/09/24 - Shmulik Hen <shmulik.hen at intel dot com> + * - 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 "Septemer 24, 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] <master-interface> < <slave-if> [metric <N>] > ...\n" -" ifenslave -c master-interface slave-if\n"; +"Usage: ifenslave [-f] <master-if> <slave-if> [<slave-if>...]\n" +" ifenslave -d <master-if> <slave-if> [<slave-if>...]\n" +" ifenslave -c <master-if> <slave-if>\n" +" ifenslave --help\n"; -static const char *howto_msg = -"Usage: ifenslave [-adfrvVh] <master-interface> < <slave-if> [metric <N>] > ...\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 @@ static const char *howto_msg = " - assign an IP address to the bond device :\n" " # ifconfig bond0 <addr> netmask <mask> broadcast <bcast>\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 <unistd.h> @@ -153,476 +171,332 @@ typedef __uint8_t u8; /* ditto */ #include <linux/ethtool.h> 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; +}; -static void if_print(char *ifname); -static int get_abi_ver(char *master_ifname); +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} +}; -int -main(int argc, char **argv) +static void if_print(char *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[]) { - 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++; - } - - /* option check */ - if (opt_c) - if(opt_a || opt_f || opt_r || opt_d || verbose || opt_version || - opt_howto || 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; + + 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 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)); - } - } + /* 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; + } - /* 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 short mif_flags; 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 @@ static int if_getconfig(char *ifname) } else netmask = ifr.ifr_netmask; - return(0); + return 0; } static void if_print(char *ifname) @@ -705,15 +578,16 @@ static void if_print(char *ifname) 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 @@ static void if_print(char *ifname) /*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 @@ static int get_abi_ver(char *master_ifname) 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; + } + + 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; + } + +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; } - if (verbose) { - printf("ABI ver is %d\n", abi_ver); + 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 abi_ver; + + 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 @@ static int get_abi_ver(char *master_ifname) * compile-command: "gcc -Wall -Wstrict-prototypes -O -I/usr/src/linux/include ifenslave.c -o ifenslave" * End: */ + diff --git a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c index d62cc282bf28..337a9f8f6e2f 100644 --- a/drivers/char/pcmcia/synclink_cs.c +++ b/drivers/char/pcmcia/synclink_cs.c @@ -244,7 +244,6 @@ typedef struct _mgslpc_info { char netname[10]; struct net_device *netdev; struct net_device_stats netstats; - struct net_device netdevice; #endif } MGSLPC_INFO; @@ -4206,35 +4205,46 @@ void tx_timeout(unsigned long context) #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 @@ void mgslpc_sppp_delete(MGSLPC_INFO *info) { 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 --git a/drivers/char/synclink.c b/drivers/char/synclink.c index 585196d778f9..8e4f37ede022 100644 --- a/drivers/char/synclink.c +++ b/drivers/char/synclink.c @@ -327,7 +327,6 @@ struct mgsl_struct { char netname[10]; struct net_device *netdev; struct net_device_stats netstats; - struct net_device netdevice; #endif }; @@ -737,8 +736,8 @@ int mgsl_ioctl_common(struct mgsl_struct *info, unsigned int cmd, unsigned long #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 @@ int usc_loopmode_send_active( struct mgsl_struct * info ) #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 @@ void mgsl_sppp_delete(struct mgsl_struct *info) { 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 --git a/drivers/char/synclinkmp.c b/drivers/char/synclinkmp.c index 82c7afe29f92..f60282147e07 100644 --- a/drivers/char/synclinkmp.c +++ b/drivers/char/synclinkmp.c @@ -289,7 +289,6 @@ typedef struct _synclinkmp_info { char netname[10]; struct net_device *netdev; struct net_device_stats netstats; - struct net_device netdevice; #endif } SLMP_INFO; @@ -1627,35 +1626,44 @@ static void set_break(struct tty_struct *tty, int break_state) /* 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 @@ static void sppp_delete(SLMP_INFO *info) { 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 --git a/drivers/ieee1394/eth1394.c b/drivers/ieee1394/eth1394.c index a4143add8fbf..230ac0bf2e8e 100644 --- a/drivers/ieee1394/eth1394.c +++ b/drivers/ieee1394/eth1394.c @@ -395,8 +395,8 @@ static void ether1394_reset_priv (struct net_device *dev, int set_mtu) } } -/* 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 @@ static int ether1394_init_dev (struct net_device *dev) dev->type = ARPHRD_IEEE1394; ether1394_reset_priv (dev, 1); - - return 0; } /* @@ -461,8 +459,6 @@ static void ether1394_add_host (struct hpsb_host *host) SET_MODULE_OWNER(dev); - dev->init = ether1394_init_dev; - priv = (struct eth1394_priv *)dev->priv; spin_lock_init(&priv->lock); @@ -483,6 +479,8 @@ static void ether1394_add_host (struct hpsb_host *host) 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 @@ static void ether1394_add_host (struct hpsb_host *host) out: if (dev != NULL) - kfree(dev); + free_netdev(dev); if (hi) hpsb_destroy_hostinfo(ð1394_highlevel, host); diff --git a/drivers/net/3c503.c b/drivers/net/3c503.c index c82c01b6f608..1a0ca52dfd51 100644 --- a/drivers/net/3c503.c +++ b/drivers/net/3c503.c @@ -145,12 +145,11 @@ static void cleanup_card(struct net_device *dev) { /* NB: el2_close() handles free_irq */ release_region(dev->base_addr, EL2_IO_EXTENT); - kfree(dev->priv); } struct net_device * __init el2_probe(int unit) { - struct net_device *dev = alloc_etherdev(0); + struct net_device *dev = alloc_ei_netdev(); int err; if (!dev) @@ -159,8 +158,6 @@ struct net_device * __init el2_probe(int unit) sprintf(dev->name, "eth%d", unit); netdev_boot_setup_check(dev); - dev->priv = NULL; /* until all 8390-based use alloc_etherdev() */ - err = do_el2_probe(dev); if (err) goto out; @@ -228,12 +225,6 @@ el2_probe1(struct net_device *dev, int ioaddr) 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 out1; - } printk("%s: 3c503 at i/o base %#3x, node ", dev->name, ioaddr); @@ -699,10 +690,9 @@ init_module(void) if (this_dev != 0) break; /* only autoprobe 1st one */ printk(KERN_NOTICE "3c503.c: Presently autoprobing (not recommended) for a single card.\n"); } - dev = alloc_etherdev(0); + dev = alloc_ei_netdev(); if (!dev) break; - dev->priv = NULL; dev->irq = irq[this_dev]; dev->base_addr = io[this_dev]; dev->mem_end = xcvr[this_dev]; /* low 4bits = xcvr sel. */ diff --git a/drivers/net/8390.c b/drivers/net/8390.c index 7e5e81139a04..eb33f04a1ad8 100644 --- a/drivers/net/8390.c +++ b/drivers/net/8390.c @@ -157,15 +157,8 @@ static void do_set_multicast_list(struct net_device *dev); 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_open(struct net_device *dev) */ 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 @@ int ei_close(struct net_device *dev) 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 @@ void ei_tx_timeout(struct net_device *dev) 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 @@ irqreturn_t ei_interrupt(int irq, void *dev_id, struct pt_regs * regs) } 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. @@ -540,7 +533,7 @@ irqreturn_t ei_interrupt(int irq, void *dev_id, struct pt_regs * regs) 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 +576,7 @@ static void ei_tx_err(struct net_device *dev) 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 +668,7 @@ static void ei_tx_intr(struct net_device *dev) 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 +806,7 @@ static void ei_rx_overrun(struct net_device *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 @@ -881,7 +874,7 @@ static void ei_rx_overrun(struct net_device *dev) 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 +929,7 @@ static void do_set_multicast_list(struct net_device *dev) { 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 +983,34 @@ static void do_set_multicast_list(struct net_device *dev) 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 +1018,10 @@ static void __ethdev_init(struct net_device *dev) * * 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 +1041,7 @@ struct net_device *alloc_ei_netdev(void) 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 +1105,7 @@ static void NS8390_trigger_send(struct net_device *dev, unsigned int length, 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); @@ -1156,9 +1125,8 @@ EXPORT_SYMBOL(ei_open); EXPORT_SYMBOL(ei_close); EXPORT_SYMBOL(ei_interrupt); 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 --git a/drivers/net/8390.h b/drivers/net/8390.h index f3415b7ab3f7..1587a22ad9b4 100644 --- a/drivers/net/8390.h +++ b/drivers/net/8390.h @@ -39,12 +39,15 @@ extern int ei_debug; #define ei_debug 1 #endif -extern int ethdev_init(struct net_device *dev); 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 +87,7 @@ struct ei_device { /* 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 --git a/drivers/net/Space.c b/drivers/net/Space.c index 4da8f077de9a..820e5afa6b89 100644 --- a/drivers/net/Space.c +++ b/drivers/net/Space.c @@ -74,7 +74,7 @@ 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(struct net_device *); +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); @@ -86,7 +86,7 @@ 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(struct net_device *dev); +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); @@ -326,17 +326,17 @@ static void __init ethif_probe2(int unit) if (base_addr == 1) return; - 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); + (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 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); @@ -356,26 +356,19 @@ static struct devprobe2 tr_probes2[] __initdata = { 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 - 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) diff --git a/drivers/net/a2065.c b/drivers/net/a2065.c index 143c3ef8bc52..05aa7d5e80bc 100644 --- a/drivers/net/a2065.c +++ b/drivers/net/a2065.c @@ -737,7 +737,7 @@ static int __init a2065_probe(void) continue; } - dev = alloc_etherdev(0, sizeof(struct lance_private)); + dev = alloc_etherdev(sizeof(struct lance_private)); if (dev == NULL) { release_resource(r1); diff --git a/drivers/net/ac3200.c b/drivers/net/ac3200.c index c450bc17d12c..cb25422bfe1d 100644 --- a/drivers/net/ac3200.c +++ b/drivers/net/ac3200.c @@ -128,12 +128,11 @@ static void cleanup_card(struct net_device *dev) release_region(dev->base_addr, AC_IO_EXTENT); if (ei_status.reg0) iounmap((void *)dev->mem_start); - kfree(dev->priv); } struct net_device * __init ac3200_probe(int unit) { - struct net_device *dev = alloc_etherdev(0); + struct net_device *dev = alloc_ei_netdev(); int err; if (!dev) @@ -142,8 +141,6 @@ struct net_device * __init ac3200_probe(int unit) sprintf(dev->name, "eth%d", unit); netdev_boot_setup_check(dev); - dev->priv = NULL; /* until all 8390-based use alloc_etherdev() */ - err = do_ac3200_probe(dev); if (err) goto out; @@ -197,13 +194,6 @@ static int __init ac_probe1(int ioaddr, struct net_device *dev) } #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)); @@ -251,7 +241,7 @@ static int __init ac_probe1(int ioaddr, struct net_device *dev) 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) { @@ -259,7 +249,7 @@ static int __init ac_probe1(int ioaddr, struct net_device *dev) 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", @@ -288,11 +278,8 @@ static int __init ac_probe1(int ioaddr, struct net_device *dev) dev->stop = &ac_close_card; 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; @@ -401,10 +388,9 @@ init_module(void) for (this_dev = 0; this_dev < MAX_AC32_CARDS; this_dev++) { if (io[this_dev] == 0 && this_dev != 0) break; - dev = alloc_etherdev(0); + dev = alloc_ei_netdev(); if (!dev) break; - dev->priv = NULL; dev->irq = irq[this_dev]; dev->base_addr = io[this_dev]; dev->mem_start = mem[this_dev]; /* Currently ignored by driver */ diff --git a/drivers/net/apne.c b/drivers/net/apne.c index bd9e73294501..9070b1d154d1 100644 --- a/drivers/net/apne.c +++ b/drivers/net/apne.c @@ -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); @@ -138,10 +138,9 @@ struct net_device * __init apne_probe(int unit) return ERR_PTR(-ENODEV); } - dev = alloc_etherdev(0); + dev = alloc_ei_netdev(); if (!dev) return ERR_PTR(-ENOMEM); - dev->priv = NULL; if (unit >= 0) { sprintf(dev->name, "eth%d", unit); netdev_boot_setup_check(dev); @@ -314,13 +313,6 @@ static int __init apne_probe1(struct net_device *dev, int ioaddr) 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]; @@ -572,8 +564,6 @@ static struct net_device *apne_dev; int init_module(void) { - int err; - apne_dev = apne_probe(-1); if (IS_ERR(apne_dev)) return PTR_ERR(apne_dev); diff --git a/drivers/net/appletalk/ipddp.c b/drivers/net/appletalk/ipddp.c index ee8b64aba963..8c0a962d538f 100644 --- a/drivers/net/appletalk/ipddp.c +++ b/drivers/net/appletalk/ipddp.c @@ -28,6 +28,7 @@ #include <linux/kernel.h> #include <linux/init.h> #include <linux/netdevice.h> +#include <linux/etherdevice.h> #include <linux/ip.h> #include <linux/atalk.h> #include <linux/if_arp.h> @@ -55,34 +56,24 @@ static struct ipddp_route* ipddp_find_route(struct ipddp_route *rt); 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 <johns393@maroon.tc.umn.edu>\n", - dev->name); - if(ipddp_mode == IPDDP_DECAP) - printk("%s: Appletalk-IP Decap. mode by Jay Schulist <jschlst@samba.org>\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 @@ static int __init ipddp_init(struct net_device *dev) */ 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 <johns393@maroon.tc.umn.edu>\n", + dev->name); + if(ipddp_mode == IPDDP_DECAP) + printk("%s: Appletalk-IP Decap. mode by Jay Schulist <jschlst@samba.org>\n", + dev->name); + + return dev; } /* @@ -281,23 +286,16 @@ static int ipddp_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) } } -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 @@ static void __exit ipddp_cleanup_module(void) { 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 --git a/drivers/net/arcnet/arc-rimi.c b/drivers/net/arcnet/arc-rimi.c index 9530fb4cddd0..77ff7df32236 100644 --- a/drivers/net/arcnet/arc-rimi.c +++ b/drivers/net/arcnet/arc-rimi.c @@ -26,6 +26,7 @@ */ #include <linux/kernel.h> #include <linux/module.h> +#include <linux/moduleparam.h> #include <linux/ioport.h> #include <linux/slab.h> #include <linux/delay.h> @@ -85,8 +86,6 @@ static void arcrimi_copy_from_card(struct net_device *dev, int bufnum, int offse */ 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 @@ static int __init arcrimi_probe(struct net_device *dev) "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_probe(struct net_device *dev) 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 @@ static int __init arcrimi_found(struct net_device *dev) /* 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 @@ static int __init arcrimi_found(struct net_device *dev) 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 @@ static int __init arcrimi_found(struct net_device *dev) * 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 @@ static void arcrimi_copy_from_card(struct net_device *dev, int bufnum, int offse TIME("memcpy_fromio", count, memcpy_fromio(buf, memaddr, count)); } -#ifdef MODULE - -static struct net_device *my_dev; +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 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_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"); -int init_module(void) +static struct net_device *my_dev; + +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 --git a/drivers/net/arcnet/arcnet.c b/drivers/net/arcnet/arcnet.c index 1de786ca7f75..57c1b7d2d362 100644 --- a/drivers/net/arcnet/arcnet.c +++ b/drivers/net/arcnet/arcnet.c @@ -92,6 +92,7 @@ EXPORT_SYMBOL(arc_proto_null); 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 @@ void arcdev_setup(struct net_device *dev) 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 --git a/drivers/net/arcnet/com20020-isa.c b/drivers/net/arcnet/com20020-isa.c index 1d7100987c67..d94940de3ec9 100644 --- a/drivers/net/arcnet/com20020-isa.c +++ b/drivers/net/arcnet/com20020-isa.c @@ -26,6 +26,7 @@ * ********************** */ #include <linux/module.h> +#include <linux/moduleparam.h> #include <linux/kernel.h> #include <linux/types.h> #include <linux/ioport.h> @@ -117,49 +118,41 @@ out: 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 @@ int init_module(void) 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 @@ static int __init com20020isa_setup(char *s) 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 --git a/drivers/net/arcnet/com20020-pci.c b/drivers/net/arcnet/com20020-pci.c index 6ae9f59559af..96636ca8754e 100644 --- a/drivers/net/arcnet/com20020-pci.c +++ b/drivers/net/arcnet/com20020-pci.c @@ -27,6 +27,7 @@ * ********************** */ #include <linux/module.h> +#include <linux/moduleparam.h> #include <linux/kernel.h> #include <linux/types.h> #include <linux/ioport.h> @@ -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 @@ static int __devinit com20020pci_probe(struct pci_dev *pdev, const struct pci_de 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 @@ static int __devinit com20020pci_probe(struct pci_dev *pdev, const struct pci_de 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 @@ static int __devinit com20020pci_probe(struct pci_dev *pdev, const struct pci_de 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 @@ static int __devinit com20020pci_probe(struct pci_dev *pdev, const struct pci_de 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 --git a/drivers/net/arcnet/com20020.c b/drivers/net/arcnet/com20020.c index 6b76a5f8b7ab..7fa829eef427 100644 --- a/drivers/net/arcnet/com20020.c +++ b/drivers/net/arcnet/com20020.c @@ -172,11 +172,6 @@ int com20020_found(struct net_device *dev, int shared) 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 @@ int com20020_found(struct net_device *dev, int shared) 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 @@ static void com20020_set_mc_list(struct net_device *dev) } } -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 --git a/drivers/net/arcnet/com90io.c b/drivers/net/arcnet/com90io.c index 563b76b006a7..ac2e0ffb2dc2 100644 --- a/drivers/net/arcnet/com90io.c +++ b/drivers/net/arcnet/com90io.c @@ -27,6 +27,7 @@ */ #include <linux/kernel.h> #include <linux/module.h> +#include <linux/moduleparam.h> #include <linux/ioport.h> #include <linux/slab.h> #include <linux/delay.h> @@ -234,6 +235,7 @@ static int __init com90io_found(struct net_device *dev) { 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 @@ static int __init com90io_found(struct net_device *dev) 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 @@ static int __init com90io_found(struct net_device *dev) 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 @@ static int __init com90io_found(struct net_device *dev) 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 @@ static void com90io_copy_from_card(struct net_device *dev, int bufnum, int offse 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 @@ void cleanup_module(void) 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 --git a/drivers/net/arcnet/com90xx.c b/drivers/net/arcnet/com90xx.c index 50d959b300c6..0f51997ca603 100644 --- a/drivers/net/arcnet/com90xx.c +++ b/drivers/net/arcnet/com90xx.c @@ -25,6 +25,7 @@ * ********************** */ #include <linux/module.h> +#include <linux/moduleparam.h> #include <linux/init.h> #include <linux/ioport.h> #include <linux/delay.h> @@ -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 numcards; 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 @@ static int __init com90xx_probe(struct net_device *dev) 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 @@ static int __init com90xx_probe(struct net_device *dev) 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 @@ static int __init com90xx_probe(struct net_device *dev) * 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 @@ static int __init com90xx_probe(struct net_device *dev) 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 @@ static int __init com90xx_probe(struct net_device *dev) 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 @@ static int __init com90xx_probe(struct net_device *dev) 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 @@ static int __init com90xx_probe(struct net_device *dev) 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 @@ static int __init com90xx_probe(struct net_device *dev) * 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 @@ static int __init com90xx_probe(struct net_device *dev) 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 @@ static int __init com90xx_probe(struct net_device *dev) 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 @@ static int __init com90xx_probe(struct net_device *dev) 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 @@ static int __init com90xx_probe(struct net_device *dev) 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 @@ static int __init com90xx_probe(struct net_device *dev) 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 @@ static int __init com90xx_found(struct net_device *dev0, int ioaddr, int airq, 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 @@ static int __init com90xx_found(struct net_device *dev0, int ioaddr, int airq, 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 @@ static int __init com90xx_found(struct net_device *dev0, int ioaddr, int airq, 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 @@ static void com90xx_copy_from_card(struct net_device *dev, int bufnum, int offse } -/* 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 @@ static void __exit com90xx_exit(void) 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 @@ static int __init com90xx_setup(char *s) } if (*s) - strncpy(device, s, 9); - else - strcpy(device, "arc%d"); + snprintf(device, sizeof(device), "%s", s); return 1; } diff --git a/drivers/net/arm/etherh.c b/drivers/net/arm/etherh.c index e7d45d8a5d3e..4d9733710238 100644 --- a/drivers/net/arm/etherh.c +++ b/drivers/net/arm/etherh.c @@ -551,15 +551,12 @@ etherh_probe(struct expansion_card *ec, const struct ecard_id *id) 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 @@ etherh_probe(struct expansion_card *ec, const struct ecard_id *id) 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"; diff --git a/drivers/net/bonding/bond_3ad.c b/drivers/net/bonding/bond_3ad.c index 3431b2e08996..f222d766d190 100644 --- a/drivers/net/bonding/bond_3ad.c +++ b/drivers/net/bonding/bond_3ad.c @@ -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/09/24 - Shmulik Hen <shmulik.hen at intel dot com> + * - Code cleanup and style changes */ +//#define BONDING_DEBUG 1 + #include <linux/skbuff.h> #include <linux/if_ether.h> #include <linux/netdevice.h> @@ -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 bonding *__get_bond_by_port(struct port *port) */ 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 @@ static inline struct port *__get_next_port(struct port *port) 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 @@ static inline struct aggregator *__get_first_agg(struct port *port) { 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 @@ static inline struct aggregator *__get_next_agg(struct aggregator *aggregator) 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 @@ static u16 __get_link_speed(struct port *port) } } - 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 @@ static u8 __get_duplex(struct port *port) 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 @@ static void ad_mux_machine(struct port *port) // 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 @@ static void ad_rx_machine(struct lacpdu *lacpdu, struct port *port) // 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 @@ static void ad_rx_machine(struct lacpdu *lacpdu, struct port *port) // 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 @@ static void ad_tx_machine(struct port *port) __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 @@ static void ad_periodic_machine(struct port *port) // 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 @@ static void ad_port_selection_logic(struct port *port) 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 @@ static void ad_port_selection_logic(struct port *port) } } 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 @@ static void ad_port_selection_logic(struct port *port) 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 @@ static void ad_port_selection_logic(struct port *port) // 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 @@ static void ad_agg_selection_logic(struct aggregator *aggregator) 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 @@ static void ad_clear_agg(struct aggregator *aggregator) 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_initialize_port(struct port *port, int lacp_fast) 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_enable_collecting_distributing(struct port *port) 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 @@ static void ad_marker_info_send(struct port *port) // 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 @@ static void ad_marker_info_received(struct marker *marker_info,struct port *port // 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 @@ static u16 aggregator_identifier; 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 @@ int bond_3ad_bind_slave(struct slave *slave) 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 @@ int bond_3ad_bind_slave(struct slave *slave) 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 @@ void bond_3ad_unbind_slave(struct slave *slave) // 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 @@ void bond_3ad_unbind_slave(struct slave *slave) // 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 @@ void bond_3ad_unbind_slave(struct slave *slave) 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 @@ void bond_3ad_unbind_slave(struct slave *slave) } } - 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 @@ void bond_3ad_state_machine_handler(struct bonding *bond) 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 @@ void bond_3ad_state_machine_handler(struct bonding *bond) // 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 @@ void bond_3ad_state_machine_handler(struct bonding *bond) // 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 @@ void bond_3ad_state_machine_handler(struct bonding *bond) } } -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 @@ void bond_3ad_rx_indication(struct lacpdu *lacpdu, struct slave *slave, u16 leng 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 @@ void bond_3ad_rx_indication(struct lacpdu *lacpdu, struct slave *slave, u16 leng 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 @@ void bond_3ad_adapter_speed_changed(struct slave *slave) // 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 @@ void bond_3ad_adapter_duplex_changed(struct slave *slave) // 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 @@ void bond_3ad_handle_link_change(struct slave *slave, char link) // 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_get_active_agg_info(struct bonding *bond, struct ad_info *ad_info) 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 @@ int bond_3ad_xmit_xor(struct sk_buff *skb, struct net_device *dev) 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 @@ int bond_3ad_xmit_xor(struct sk_buff *skb, struct net_device *dev) 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 @@ int bond_3ad_xmit_xor(struct sk_buff *skb, struct net_device *dev) 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 --git a/drivers/net/bonding/bond_3ad.h b/drivers/net/bonding/bond_3ad.h index 12a5d20ca1b7..1d53bfb04e25 100644 --- a/drivers/net/bonding/bond_3ad.h +++ b/drivers/net/bonding/bond_3ad.h @@ -28,6 +28,9 @@ * 2003/05/01 - Shmulik Hen <shmulik.hen at intel dot com> * - Renamed bond_3ad_link_status_changed() to * bond_3ad_handle_link_change() for compatibility with TLB. + * + * 2003/09/24 - Shmulik Hen <shmulik.hen at intel dot com> + * - Code cleanup and style changes */ #ifndef __BOND_3AD_H__ diff --git a/drivers/net/bonding/bond_alb.c b/drivers/net/bonding/bond_alb.c index 544cbe4aa835..a853d9e41598 100644 --- a/drivers/net/bonding/bond_alb.c +++ b/drivers/net/bonding/bond_alb.c @@ -28,8 +28,13 @@ * 2003/08/06 - Amir Noam <amir.noam at intel dot com> * - Add support for setting bond's MAC address with special * handling required for ALB/TLB. + * + * 2003/09/24 - Shmulik Hen <shmulik.hen at intel dot com> + * - Code cleanup and style changes */ +//#define BONDING_DEBUG 1 + #include <linux/skbuff.h> #include <linux/netdevice.h> #include <linux/etherdevice.h> @@ -50,11 +55,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 +71,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 +91,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 +118,12 @@ struct arp_pkt { /* 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; i<hash_size; i++) { + for (i = 0; i < hash_size; i++) { hash ^= hash_start[i]; } @@ -125,193 +132,151 @@ _simple_hash(u8 *hash_start, int hash_size) /*********************** tlb specific functions ***************************/ -static inline void -_lock_tx_hashtbl(struct bonding *bond) +static inline void _lock_tx_hashtbl(struct bonding *bond) { spin_lock(&(BOND_ALB_INFO(bond).tx_hashtbl_lock)); } -static inline void -_unlock_tx_hashtbl(struct bonding *bond) +static inline void _unlock_tx_hashtbl(struct bonding *bond) { spin_unlock(&(BOND_ALB_INFO(bond).tx_hashtbl_lock)); } /* Caller must hold tx_hashtbl lock */ -static inline void -tlb_init_table_entry(struct bonding *bond, u8 index, u8 save_load) +static inline void tlb_init_table_entry(struct tlb_client_info *entry, int save_load) { - struct tlb_client_info *entry; - - if (BOND_ALB_INFO(bond).tx_hashtbl == NULL) { - return; - } - - entry = &(BOND_ALB_INFO(bond).tx_hashtbl[index]); - /* at end of cycle, save the load that was transmitted to the client - * during the cycle, and set the tx_bytes counter to 0 for counting - * the load during the next cycle - */ if (save_load) { entry->load_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; i<TLB_HASH_TABLE_SIZE; i++) { - tlb_init_table_entry(bond, i, 1); + + for (i = 0; i < TLB_HASH_TABLE_SIZE; i++) { + tlb_init_table_entry(&bond_info->tx_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 +310,12 @@ tlb_choose_channel(struct bonding *bond, u32 hash_index, u32 skb_len) } /*********************** 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 +323,20 @@ _unlock_rx_hashtbl(struct bonding *bond) /* 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 +346,60 @@ rlb_update_entry_from_arp(struct bonding *bond, struct arp_pkt *arp) _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 +415,41 @@ rlb_next_rx_slave(struct bonding *bond) /* 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 +477,24 @@ rlb_clear_slave(struct bonding *bond, struct slave *slave) _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; i<RLB_ARP_BURST_SIZE; i++) { + for (i = 0; i < RLB_ARP_BURST_SIZE; i++) { arp_send(ARPOP_REPLY, ETH_P_ARP, client_info->ip_dst, client_info->slave->dev, @@ -561,20 +506,14 @@ rlb_update_client(struct rlb_client_info *client_info) } /* 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 +534,15 @@ rlb_update_rx_clients(struct bonding *bond) } /* 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 +565,31 @@ rlb_req_update_slave_clients(struct bonding *bond, struct slave *slave) } /* 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 +600,22 @@ rlb_req_update_subnet_clients(struct bonding *bond, u32 src_ip) } /* 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 +628,12 @@ rlb_choose_channel(struct bonding *bond, struct arp_pkt *arp) } } 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 +654,7 @@ rlb_choose_channel(struct bonding *bond, struct arp_pkt *arp) 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 +677,9 @@ rlb_choose_channel(struct bonding *bond, struct arp_pkt *arp) /* 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 +692,8 @@ rlb_arp_xmit(struct sk_buff *skb, struct bonding *bond) 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 +712,29 @@ rlb_arp_xmit(struct sk_buff *skb, struct bonding *bond) * 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 +749,83 @@ rlb_rebalance(struct bonding *bond) } /* 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; i<RLB_HASH_TABLE_SIZE; i++) { + for (i = 0; i < RLB_HASH_TABLE_SIZE; i++) { rlb_init_table_entry(bond_info->rx_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 +833,26 @@ alb_send_learning_packets(struct slave *slave, u8 mac_addr[]) 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 +863,23 @@ alb_set_slave_mac_addr(struct slave *slave, u8 addr[], int hw) 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 +896,7 @@ alb_swap_mac_addr(struct bonding *bond, */ rlb_req_update_slave_clients(bond, slave1); } - } - else { + } else { disabled_slave = slave1; } @@ -1017,15 +908,14 @@ alb_swap_mac_addr(struct bonding *bond, */ 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 +933,8 @@ alb_swap_mac_addr(struct bonding *bond, * * 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 +942,23 @@ alb_change_hw_addr_on_detach(struct bonding *bond, struct slave *slave) 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 +989,10 @@ alb_change_hw_addr_on_detach(struct bonding *bond, struct slave *slave) * 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; + int i, j, found = 0; if (bond->slave_cnt == 0) { /* this is the first slave */ @@ -1112,65 +1003,68 @@ alb_handle_addr_collision_on_attach(struct bonding *bond, struct slave *slave) * 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 (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); + 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 { - 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_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 +1082,36 @@ alb_handle_addr_collision_on_attach(struct bonding *bond, struct slave *slave) * * 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 +1119,23 @@ alb_set_mac_address(struct bonding *bond, void *addr) 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 +1157,7 @@ bond_alb_initialize(struct bonding *bond, int rlb_enabled) 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 +1168,38 @@ bond_alb_deinitialize(struct bonding *bond) } } -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 +1207,8 @@ bond_alb_xmit(struct sk_buff *skb, struct net_device *dev) } 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)) { @@ -1349,14 +1230,12 @@ bond_alb_xmit(struct sk_buff *skb, struct net_device *dev) 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 +1248,16 @@ bond_alb_xmit(struct sk_buff *skb, struct net_device *dev) 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 +1265,35 @@ bond_alb_xmit(struct sk_buff *skb, struct net_device *dev) 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 +1301,53 @@ bond_alb_monitor(struct bonding *bond) /* 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 +1355,13 @@ bond_alb_monitor(struct bonding *bond) * 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 +1381,23 @@ bond_alb_monitor(struct bonding *bond) } } +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 +1405,12 @@ bond_alb_init_slave(struct bonding *bond, struct slave *slave) */ 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 +1426,7 @@ bond_alb_init_slave(struct bonding *bond, struct slave *slave) } /* 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 +1441,7 @@ bond_alb_deinit_slave(struct bonding *bond, struct slave *slave) } /* 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 +1465,111 @@ bond_alb_handle_link_change(struct bonding *bond, struct slave *slave, } /** - * 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 --git a/drivers/net/bonding/bond_alb.h b/drivers/net/bonding/bond_alb.h index d3f4291706ef..9dc848dea5f1 100644 --- a/drivers/net/bonding/bond_alb.h +++ b/drivers/net/bonding/bond_alb.h @@ -24,6 +24,9 @@ * 2003/08/06 - Amir Noam <amir.noam at intel dot com> * - Add support for setting bond's MAC address with special * handling required for ALB/TLB. + * + * 2003/09/24 - Shmulik Hen <shmulik.hen at intel dot com> + * - Code cleanup and style changes */ #ifndef __BOND_ALB_H__ @@ -126,10 +129,10 @@ void bond_alb_deinitialize(struct bonding *bond); 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 --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 5bed2092693e..9360c8bbb2b1 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -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 <ctindel at ieee dot org> * - Ported to 2.4 Kernel - * + * * 2001/5/2 - Jeffrey E. Mast <jeff at mastfamily dot com> * - 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 <jeff at mastfamily dot com> - * - 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 <ctindel at ieee dot org> * - Added /proc support for getting bond and slave information. - * Information is in /proc/net/<bond device>/info. + * Information is in /proc/net/<bond device>/info. * - Changed the locking when calling bond_close to prevent deadlock. * * 2001/8/05 - Janice Girouard <girouard at us.ibm.com> @@ -144,8 +144,8 @@ * but only for an up link. * * 2001/9/20 - Chad N. Tindel <ctindel at ieee dot org> - * - 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 <girouard at us.ibm.com> @@ -155,10 +155,10 @@ * - Various memory leak fixes * * 2001/11/5 - Mark Huth <mark dot huth at mvista dot com> - * - 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 <kameshwara.rao * wipro_com> - * - 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 <tony.cureington * hp_com> * - 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 <laurent.deniel at free.fr> * - 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 <laurent.deniel at free.fr> @@ -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 <fubar at us dot ibm dot com> * - 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 <shmulik.hen at intel dot com> - * - 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 <shmulik.hen at intel dot com> * - 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,36 @@ * - 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 <amir.noam at intel dot com> + * - Fix /proc creation/destruction. + * + * 2003/12/01 - Shmulik Hen <shmulik.hen at intel dot com> + * - 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. */ +//#define BONDING_DEBUG 1 + #include <linux/config.h> #include <linux/kernel.h> #include <linux/module.h> @@ -452,7 +480,6 @@ #include <asm/dma.h> #include <asm/uaccess.h> #include <linux/errno.h> - #include <linux/netdevice.h> #include <linux/inetdevice.h> #include <linux/etherdevice.h> @@ -461,58 +488,72 @@ #include <linux/rtnetlink.h> #include <linux/proc_fs.h> #include <linux/seq_file.h> - -#include <linux/if_bonding.h> #include <linux/smp.h> #include <linux/if_ether.h> #include <net/arp.h> #include <linux/mii.h> #include <linux/ethtool.h> +#include <linux/if_bonding.h> #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 +#define MAX_ARP_IP_TARGETS 16 -#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[MAX_ARP_IP_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(MAX_ARP_IP_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[MAX_ARP_IP_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 +562,16 @@ static int orig_app_abi_ver = -1; /* This is used to save the first ABI version * 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,101 +584,9 @@ static struct bond_parm_tbl bond_mode_tbl[] = { { NULL, -1}, }; -static int multicast_mode = BOND_MULTICAST_ALL; -static char *multicast = NULL; - -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; +/*---------------------------- General routines -----------------------------*/ -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 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; (i<MAX_ARP_IP_TARGETS) && arp_target[i]; i++) { - arp_send(ARPOP_REQUEST, ETH_P_ARP, arp_target[i], slave->dev, - my_ip, arp_target_hw_addr, slave->dev->dev_addr, - arp_target_hw_addr); - } -} - - -static const char * -bond_mode_name(void) +static const char *bond_mode_name(void) { switch (bond_mode) { case BOND_MODE_ROUNDROBIN : @@ -657,149 +608,7 @@ bond_mode_name(void) } } -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 <slave> from the list <bond>. - * WARNING: no check is made to verify if the slave effectively - * belongs to <bond>. It returns <slave> in case it's needed. - * Nothing is freed on return, structures are just unchained. - * If the bond->current_slave pointer was pointing to <slave>, - * 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 <slave> to the list <bond>. - * - * 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,16 +618,16 @@ bond_attach_slave(struct bonding *bond, struct slave *new_slave) */ 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; + ioctl = slave_dev->do_ioctl; if (ioctl) { etool.cmd = ETHTOOL_GSET; ifr.ifr_data = (char*)&etool; - if (IOCTL(dev, &ifr, SIOCETHTOOL) == 0) { + if (IOCTL(slave_dev, &ifr, SIOCETHTOOL) == 0) { slave->speed = etool.speed; slave->duplex = etool.duplex; } else { @@ -829,20 +638,20 @@ static int bond_update_speed_duplex(struct slave *slave) } switch (slave->speed) { - case SPEED_10: - case SPEED_100: - case SPEED_1000: - break; - default: - goto err_out; + case SPEED_10: + case SPEED_100: + case SPEED_1000: + break; + default: + goto err_out; } switch (slave->duplex) { - case DUPLEX_FULL: - case DUPLEX_HALF: - break; - default: - goto err_out; + case DUPLEX_FULL: + case DUPLEX_HALF: + break; + default: + goto err_out; } return 0; @@ -854,7 +663,7 @@ err_out: return -1; } -/* +/* * if <dev> supports MII link status reporting, check its link status. * * We either do MII/ETHTOOL ioctls, or check netif_carrier_ok(), @@ -870,8 +679,7 @@ err_out: * 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 net_device *slave_dev, int reporting) { static int (* ioctl)(struct net_device *, struct ifreq *, int); struct ifreq ifr; @@ -879,10 +687,10 @@ bond_check_dev_link(struct net_device *dev, int reporting) struct ethtool_value etool; if (use_carrier) { - return netif_carrier_ok(dev) ? BMSR_LSTATUS : 0; + 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 */ @@ -898,476 +706,495 @@ bond_check_dev_link(struct net_device *dev, int reporting) /* Yes, the mii is overlaid on the ifreq.ifr_ifru */ 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) { + 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_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_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_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_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 dev_mc_list *dmi; + + for (dmi = bond_dev->mc_list; dmi; dmi = dmi->next) { + dev_mc_delete(slave_dev, dmi->dmi_addr, dmi->dmi_addrlen, 0); + } if (bond_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_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; + int i; -/* - * Push the promiscuity flag down to appropriate slaves - */ -static void bond_set_promiscuity(bonding_t *bond, int inc) -{ - slave_t *slave; + new_active = old_active = bond->curr_active_slave; - if (USES_PRIMARY(bond_mode)) { - if (bond->current_slave) { - dev_set_promiscuity(bond->current_slave->dev, inc); - } - - } 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; + mintime = updelay; + + /* 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) && + (!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_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, + (updelay - new_active->delay) * 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_mode == BOND_MODE_8023AD) { + bond_3ad_handle_link_change(new_active, BOND_LINK_UP); + } + + if ((bond_mode == BOND_MODE_TLB) || + (bond_mode == BOND_MODE_ALB)) { + bond_alb_handle_link_change(bond, new_active, BOND_LINK_UP); + } + } else { + if (USES_PRIMARY(bond_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_mode == BOND_MODE_ACTIVEBACKUP) { + if (old_active) { + bond_set_slave_inactive_flags(old_active); + } + + if (new_active) { + bond_set_slave_active_flags(new_active); + } + } - if ( !(master->flags & IFF_ALLMULTI) && (bond->flags & IFF_ALLMULTI) ) - bond_set_allmulti(bond, -1); + if (USES_PRIMARY(bond_mode)) { + bond_mc_swap(bond, new_active, old_active); + } - bond->flags = master->flags; + if ((bond_mode == BOND_MODE_TLB) || + (bond_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 <bond>. + * Nothing is freed on return, structures are just unchained. + * If any slave pointer in bond was pointing to <slave>, + * 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 <slave> to bond device <master> */ -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 +1203,19 @@ static int bond_enslave(struct net_device *master_dev, * 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 +1224,29 @@ static int bond_enslave(struct net_device *master_dev, * 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_TLB) || (bond_mode == BOND_MODE_ALB)) { - printk(KERN_ERR - "bonding: Error: to use %s mode, you must " - "upgrade ifenslave.\n", bond_mode_name()); + printk(KERN_ERR DRV_NAME + ": Error: to use %s mode, you must upgrade " + "ifenslave.\n", + bond_mode_name()); 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 +1260,29 @@ static int bond_enslave(struct net_device *master_dev, */ 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 { @@ -1475,32 +1297,32 @@ static int bond_enslave(struct net_device *master_dev, /* 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_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) { @@ -1511,15 +1333,16 @@ static int bond_enslave(struct net_device *master_dev, } 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) { + if (miimon && !use_carrier) { link_reporting = bond_check_dev_link(slave_dev, 1); - if ((link_reporting == -1) && (arp_interval == 0)) { + if ((link_reporting == -1) && !arp_interval) { /* * miimon is set but a bonded network driver * does not support ETHTOOL/MII and @@ -1528,115 +1351,97 @@ static int bond_enslave(struct net_device *master_dev, * 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) || + if (!miimon || (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 + 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 " + } 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) { 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_mode) && primary) { + /* if there is a primary slave, remember it */ + if (strcmp(primary, new_slave->dev->name) == 0) { + bond->primary_slave = new_slave; + } + } + + switch (bond_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 @@ -1645,40 +1450,37 @@ static int bond_enslave(struct net_device *master_dev, 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 +1494,34 @@ static int bond_enslave(struct net_device *master_dev, */ 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 +1540,12 @@ err_restore_mac: err_free: kfree(new_slave); - return err; -} - -/* - * This function changes the active slave to slave <slave_dev>. - * It returns -EINVAL in the following cases. - * - <slave_dev> is not found in the list. - * - There is not active slave now. - * - <slave_dev> is already active. - * - The link state of <slave_dev> is not BOND_LINK_UP. - * - <slave_dev> 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 <slave> from the bond device <master> - * 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 +1554,190 @@ static void reselect_active_interface(struct bonding *bond) * 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; struct sockaddr addr; - - if (master == NULL || slave == NULL) { - return -ENODEV; - } + int mac_addr_differ; - bond = (struct bonding *) master->priv; - - /* 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 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; } 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); - } - /* 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); - } + 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; + } - printk (KERN_INFO "%s: releasing %s interface %s\n", - master->name, - (our_slave->state == BOND_STATE_ACTIVE) ? "active" : "backup", - 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_mode == BOND_MODE_8023AD) { + /* must be called before the slave is + * detached from the list + */ + bond_3ad_unbind_slave(slave); + } - /* release the slave from its bond */ - bond_detach_slave(bond, 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); - if (bond->primary_slave == our_slave) { - bond->primary_slave = NULL; - } + bond->current_arp_slave = NULL; - if (bond->current_slave == our_slave) { - change_active_interface(bond, NULL); - reselect_active_interface(bond); - } + /* release the slave from its bond */ + bond_detach_slave(bond, slave); - if (bond->current_slave == NULL) { - printk(KERN_INFO - "%s: now running without any active interface !\n", - master->name); - } + if (bond->primary_slave == slave) { + bond->primary_slave = 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->curr_active_slave == slave) { + bond_change_active_slave(bond, NULL); + bond_select_active_slave(bond); + } - break; - } + if (!bond->curr_active_slave) { + printk(KERN_INFO DRV_NAME + ": %s: now running without any active " + "interface !\n", + bond_dev->name); + } + 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 curr_active_slave + * has been replaced (if our_slave == old_current) + */ + bond_alb_deinit_slave(bond, slave); } + 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_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); + 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)) { /* 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 +1746,23 @@ static int bond_release_all(struct net_device *master) */ 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_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 (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_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 +1772,7 @@ static int bond_release_all(struct net_device *master) 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 +1780,11 @@ static int bond_release_all(struct net_device *master) /* 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 +1794,234 @@ static int bond_release_all(struct net_device *master) * 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 <slave_dev>. + * It returns -EINVAL in the following cases. + * - <slave_dev> is not found in the list. + * - There is not active slave now. + * - <slave_dev> is already active. + * - The link state of <slave_dev> is not BOND_LINK_UP. + * - <slave_dev> 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; + + /* 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_mode; + info->miimon = 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 = (miimon * HZ) / 1000; + int i; read_lock(&bond->lock); + 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(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; + 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 (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_mode == BOND_MODE_ACTIVEBACKUP) + ? ((slave == oldcurrent) + ? "active " : "backup ") + : "") + : "idle ", + slave_dev->name, + downdelay * miimon); + } } /* no break ! fall through the BOND_LINK_FAIL test to ensure proper action to be taken @@ -2300,6 +2032,7 @@ static void bond_mii_monitor(struct net_device *master) 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 */ @@ -2308,11 +2041,12 @@ static void bond_mii_monitor(struct net_device *master) 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) { @@ -2327,8 +2061,6 @@ static void bond_mii_monitor(struct net_device *master) if (slave == oldcurrent) { do_failover = 1; } - - slave_died = 1; } else { slave->delay--; } @@ -2336,12 +2068,12 @@ static void bond_mii_monitor(struct net_device *master) /* 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, + (downdelay - slave->delay) * miimon, + slave_dev->name); } break; case BOND_LINK_DOWN: /* the link was down */ @@ -2351,16 +2083,17 @@ static void bond_mii_monitor(struct net_device *master) } else { /* link going up */ slave->link = BOND_LINK_BACK; slave->delay = updelay; - - if (updelay > 0) { + + if (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, + updelay * miimon); } } /* no break ! fall through the BOND_LINK_BACK state in @@ -2370,12 +2103,13 @@ static void bond_mii_monitor(struct net_device *master) 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, + (updelay - slave->delay) * miimon, + slave_dev->name); } else { /* link stays up */ if (slave->delay == 0) { @@ -2386,8 +2120,7 @@ static void bond_mii_monitor(struct net_device *master) if (bond_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_mode != BOND_MODE_ACTIVEBACKUP) { /* make it immediately active */ slave->state = BOND_STATE_ACTIVE; } else if (slave != bond->primary_slave) { @@ -2395,12 +2128,12 @@ static void bond_mii_monitor(struct net_device *master) 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) { bond_3ad_handle_link_change(slave, BOND_LINK_UP); @@ -2411,7 +2144,7 @@ static void bond_mii_monitor(struct net_device *master) bond_alb_handle_link_change(bond, slave, BOND_LINK_UP); } - if ((oldcurrent == NULL) || + if ((!oldcurrent) || (slave == bond->primary_slave)) { do_failover = 1; } @@ -2420,7 +2153,12 @@ static void bond_mii_monitor(struct net_device *master) } } 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); @@ -2428,112 +2166,110 @@ static void bond_mii_monitor(struct net_device *master) 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: + 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 slave *slave) +{ + int i; + + for (i = 0; (i<MAX_ARP_IP_TARGETS) && arp_target[i]; i++) { + arp_send(ARPOP_REQUEST, ETH_P_ARP, arp_target[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 = (arp_interval * HZ) / 1000; + 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; + if (bond->kill_timers) { + goto out; } - if (rtnl_exlock_nowait()) { - rtnl_shunlock(); - mod_timer(&bond->arp_timer, next_timer); - return; + if (bond->slave_cnt == 0) { + goto re_arm; } - read_lock(&bond->lock); - - 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 +2277,233 @@ static void loadbalance_arp_monitor(struct net_device *master) * 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(slave); } } if (do_failover) { - write_lock(&bond->ptrlock); + write_lock(&bond->curr_slave_lock); + + bond_select_active_slave(bond); - reselect_active_interface(bond); - if (oldcurrent && !bond->current_slave) { - printk(KERN_INFO - "%s: now running without any active interface !\n", - master->name); + 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: + 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 = (arp_interval * HZ) / 1000; + int i; - if (!IS_UP(master)) { - mod_timer(&bond->arp_timer, next_timer); - return; + read_lock(&bond->lock); + + 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 +2513,66 @@ static void activebackup_arp_monitor(struct net_device *master) /* 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(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(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; + printk(KERN_INFO DRV_NAME + ": %s: backup interface %s is " + "now down.\n", + bond_dev->name, + slave->dev->name); } - - 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; - } - 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; - } - - 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); +re_arm: + mod_timer(&bond->arp_timer, jiffies + delta_in_ticks); +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 +2583,7 @@ static void *bond_info_seq_start(struct seq_file *seq, loff_t *pos) 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 +2593,7 @@ static void *bond_info_seq_start(struct seq_file *seq, loff_t *pos) 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 +2609,12 @@ static void *bond_info_seq_next(struct seq_file *seq, void *v, loff_t *pos) ++*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) @@ -3417,9 +2629,9 @@ static void bond_info_show_master(struct seq_file *seq, struct bonding *bond) { struct slave *curr; - read_lock(&bond->ptrlock); - curr = bond->current_slave; - read_unlock(&bond->ptrlock); + 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()); @@ -3435,7 +2647,6 @@ static void bond_info_show_master(struct seq_file *seq, struct bonding *bond) 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()); if (bond_mode == BOND_MODE_8023AD) { struct ad_info ad_info; @@ -3444,7 +2655,7 @@ static void bond_info_show_master(struct seq_file *seq, struct bonding *bond) 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"); @@ -3522,55 +2733,56 @@ static int bond_info_open(struct inode *inode, struct file *file) { 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 +2843,24 @@ static void bond_destroy_proc_dir(void) } #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 +2877,14 @@ static int bond_master_netdev_event(unsigned long event, struct net_device *even 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,132 +2936,856 @@ static int bond_slave_netdev_event(unsigned long event, struct net_device *event 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; + + 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; + } + + 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) { /* 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); + } - flags = event_dev->flags & (IFF_MASTER | IFF_SLAVE); - switch (flags) { - case IFF_MASTER: - res = bond_master_netdev_event(event, event_dev); + if (arp_interval) { /* arp interval, in milliseconds. */ + init_timer(arp_timer); + arp_timer->expires = jiffies + 1; + arp_timer->data = (unsigned long)bond_dev; + if (bond_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_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_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 (miimon) { /* link check interval, in milliseconds. */ + del_timer_sync(&bond->mii_timer); + } + + if (arp_interval) { /* arp interval, in milliseconds. */ + del_timer_sync(&bond->arp_timer); + } + + switch (bond_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: - /* A master that is also a slave ? */ break; } + /* Release the bonded slaves */ + bond_release_all(bond_dev); + + if ((bond_mode == BOND_MODE_TLB) || + (bond_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: + /* 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: + if (USES_PRIMARY(bond_mode)) { + res = bond_ioctl_change_active(bond_dev, slave_dev); + } else { + res = -EINVAL; + } + 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); + + /* 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. + */ -#ifdef CONFIG_PROC_FS - bond_destroy_proc_info(bond); -#endif + 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; +} + +/* + * in active-backup mode, we know that bond->curr_active_slave is always valid if + * the bond has a usable interface. + */ +static int bond_xmit_activebackup(struct sk_buff *skb, struct net_device *bond_dev) +{ + struct bonding *bond = bond_dev->priv; + + /* if we are sending arp packets, try to at least + identify our own ip address */ + if (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); + } + + read_lock(&bond->lock); + read_lock(&bond->curr_slave_lock); + + 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; + +free_out: + /* no suitable interface, frame not sent */ + dev_kfree_skb(skb); + goto out; +} + +/* + * 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 ---------------------------*/ + /* * Does not allocate but creates a /proc entry. * Allowed to fail. */ -static int __init bond_init(struct net_device *dev) +static int __init bond_init(struct net_device *bond_dev) { - struct bonding *bond; + struct bonding *bond = bond_dev->priv; int count; -#ifdef BONDING_DEBUG - printk (KERN_INFO "Begin bond_init for %s\n", dev->name); -#endif - bond = dev->priv; + dprintk("Begin bond_init for %s\n", bond_dev->name); /* initialize rwlocks */ rwlock_init(&bond->lock); - rwlock_init(&bond->ptrlock); + rwlock_init(&bond->curr_slave_lock); /* Initialize pointers */ - bond->next = bond->prev = (slave_t *)bond; - bond->current_slave = NULL; + bond->first_slave = NULL; + bond->curr_active_slave = NULL; bond->current_arp_slave = NULL; - bond->device = dev; + bond->primary_slave = NULL; + bond->dev = bond_dev; - /* Initialize the device structure. */ - dev->set_mac_address = bond_set_mac_address; + /* 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; switch (bond_mode) { - case BOND_MODE_ACTIVEBACKUP: - dev->hard_start_xmit = bond_xmit_activebackup; - break; 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; /* extern */ 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; /* extern */ + bond_dev->set_mac_address = bond_alb_set_mac_address; /* extern */ break; default: - printk(KERN_ERR "Unknown bonding mode %d\n", bond_mode); + printk(KERN_ERR DRV_NAME + ": Error: Unknown bonding mode %d\n", + bond_mode); return -EINVAL; } - 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; + 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) { + /* Initialize the device options */ + bond_dev->tx_queue_len = 0; + bond_dev->flags |= IFF_MASTER|IFF_MULTICAST; + + printk(KERN_INFO DRV_NAME ": %s registered with", bond_dev->name); + if (miimon) { printk(" MII link monitoring set to %d ms", miimon); updelay /= miimon; downdelay /= miimon; @@ -3992,50 +3794,75 @@ static int __init bond_init(struct net_device *dev) } printk(", in %s mode.\n", bond_mode_name()); - printk(KERN_INFO "%s registered with", dev->name); + printk(KERN_INFO DRV_NAME ": %s registered with", bond_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 ; count<arp_ip_count ; count++) - printk (" %s", arp_ip_target[count]); + printk(" ARP monitoring set to %d ms with %d target(s):", + arp_interval, arp_ip_count); + for (count=0 ; count<arp_ip_count ; count++) { + printk(" %s", arp_ip_target[count]); + } printk("\n"); } else { printk("out ARP monitoring\n"); } - + #ifdef CONFIG_PROC_FS - bond_create_proc_info(bond); + bond_create_proc_entry(bond); #endif - dev->destructor = 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,88 +3870,64 @@ bond_parse_parm(char *mode_arg, struct bond_parm_tbl *tbl) return -1; } - -static int __init bonding_init(void) +static int bond_check_params(void) { - 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", + printk(KERN_INFO DRV_NAME + ": lacp_rate param is irrelevant in mode %s\n", bond_mode_name()); } 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; @@ -4132,82 +3935,69 @@ static int __init bonding_init(void) /* 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"); + if (arp_interval) { + printk(KERN_WARNING DRV_NAME + ": Warning: 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; } @@ -4215,103 +4005,114 @@ static int __init bonding_init(void) /* 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); } 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); } } 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 < MAX_ARP_IP_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 && !arp_interval) { /* 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", + printk(KERN_WARNING DRV_NAME + ": Warning: %s primary device specified but has no " + "effect in %s mode\n", primary, bond_mode_name()); primary = NULL; } + return 0; +} + +static int __init bonding_init(void) +{ + int i; + int res; + + printk(KERN_INFO "%s", version); + + res = bond_check_params(); + 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; + for (i = 0; i < max_bonds; i++) { + struct net_device *bond_dev; - dev = alloc_netdev(sizeof(struct bonding), "", ether_setup); - if (!dev) { - err = -ENOMEM; + 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 +4120,18 @@ static int __init bonding_init(void) * /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); + 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 +4147,7 @@ out_err: rtnl_unlock(); - return err; + return res; } static void __exit bonding_exit(void) @@ -4362,6 +4163,8 @@ module_init(bonding_init); 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 +4173,4 @@ MODULE_DESCRIPTION(DRV_DESCRIPTION ", v" DRV_VERSION); * tab-width: 8 * End: */ + diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h index 8358c8085542..26a67de25a78 100644 --- a/drivers/net/bonding/bonding.h +++ b/drivers/net/bonding/bonding.h @@ -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 <amir.noam at intel dot com>, * Tsippy Mendelson <tsippy.mendelson at intel dot com> and @@ -22,159 +22,205 @@ * * 2003/05/01 - Shmulik Hen <shmulik.hen at intel dot com> * - Added support for Transmit load balancing mode. + * + * 2003/09/24 - Shmulik Hen <shmulik.hen at intel dot com> + * - Code cleanup and style changes */ - + #ifndef _LINUX_BONDING_H #define _LINUX_BONDING_H #include <linux/timer.h> #include <linux/proc_fs.h> +#include <linux/if_bonding.h> #include "bond_3ad.h" #include "bond_alb.h" -#ifdef BONDING_DEBUG - -// 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 DRV_VERSION "2.5.0" +#define DRV_RELDATE "December 1, 2003" +#define DRV_NAME "bonding" +#define DRV_DESCRIPTION "Ethernet Channel Bonding Driver" +#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 +/* + * Checks whether slave is ready for transmit. */ -#define SLAVE_IS_OK(slave) \ - ((((slave)->dev->flags & (IFF_UP)) == (IFF_UP)) && \ - netif_carrier_ok((slave)->dev) && \ +#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 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; +}; /** * 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 --git a/drivers/net/e2100.c b/drivers/net/e2100.c index 79700e83fc47..a6c60ccdc6d8 100644 --- a/drivers/net/e2100.c +++ b/drivers/net/e2100.c @@ -140,15 +140,13 @@ static int __init do_e2100_probe(struct net_device *dev) static void cleanup_card(struct net_device *dev) { - void *priv = dev->priv; /* NB: e21_close() handles free_irq */ release_region(dev->base_addr, E21_IO_EXTENT); - kfree(priv); } struct net_device * __init e2100_probe(int unit) { - struct net_device *dev = alloc_etherdev(0); + struct net_device *dev = alloc_ei_netdev(); int err; if (!dev) @@ -157,8 +155,6 @@ struct net_device * __init e2100_probe(int unit) sprintf(dev->name, "eth%d", unit); netdev_boot_setup_check(dev); - dev->priv = NULL; /* until all 8390-based use alloc_etherdev() */ - err = do_e2100_probe(dev); if (err) goto out; @@ -212,13 +208,6 @@ static int __init e21_probe1(struct net_device *dev, int ioaddr) 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++) @@ -228,8 +217,6 @@ static int __init e21_probe1(struct net_device *dev, int ioaddr) } if (i >= 8) { printk(" unable to get IRQ %d.\n", dev->irq); - kfree(dev->priv); - dev->priv = NULL; retval = -EAGAIN; goto out; } @@ -443,10 +430,9 @@ init_module(void) if (this_dev != 0) break; /* only autoprobe 1st one */ printk(KERN_NOTICE "e2100.c: Presently autoprobing (not recommended) for a single card.\n"); } - dev = alloc_etherdev(0); + dev = alloc_ei_netdev(); if (!dev) break; - dev->priv = NULL; dev->irq = irq[this_dev]; dev->base_addr = io[this_dev]; dev->mem_start = mem[this_dev]; diff --git a/drivers/net/es3210.c b/drivers/net/es3210.c index 21c0984f9ca2..0063813a1735 100644 --- a/drivers/net/es3210.c +++ b/drivers/net/es3210.c @@ -159,12 +159,11 @@ static void cleanup_card(struct net_device *dev) { free_irq(dev->irq, dev); release_region(dev->base_addr, ES_IO_EXTENT); - kfree(dev->priv); } struct net_device * __init es_probe(int unit) { - struct net_device *dev = alloc_etherdev(0); + struct net_device *dev = alloc_ei_netdev(); int err; if (!dev) @@ -173,8 +172,6 @@ struct net_device * __init es_probe(int unit) sprintf(dev->name, "eth%d", unit); netdev_boot_setup_check(dev); - dev->priv = NULL; /* until all 8390-based use alloc_etherdev() */ - err = do_es_probe(dev); if (err) goto out; @@ -278,13 +275,6 @@ static int __init es_probe1(struct net_device *dev, int ioaddr) 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"); @@ -437,10 +427,9 @@ init_module(void) for (this_dev = 0; this_dev < MAX_ES_CARDS; this_dev++) { if (io[this_dev] == 0 && this_dev != 0) break; - dev = alloc_etherdev(0); + dev = alloc_ei_netdev(); if (!dev) break; - dev->priv = NULL; dev->irq = irq[this_dev]; dev->base_addr = io[this_dev]; dev->mem_start = mem[this_dev]; diff --git a/drivers/net/hamradio/baycom_epp.c b/drivers/net/hamradio/baycom_epp.c index 52675b30ec21..bc85d5d0016e 100644 --- a/drivers/net/hamradio/baycom_epp.c +++ b/drivers/net/hamradio/baycom_epp.c @@ -1277,7 +1277,7 @@ static int baycom_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) * 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 @@ -1290,9 +1290,6 @@ static int baycom_probe(struct net_device *dev) }; struct baycom_state *bc; - if (!dev) - return -ENXIO; - baycom_paranoia_check(dev, "baycom_probe", -ENXIO); /* * not a real probe! only initialize data structures */ @@ -1334,8 +1331,6 @@ static int baycom_probe(struct net_device *dev) /* New style flags */ dev->flags = 0; - - return 0; } /* --------------------------------------------------------------------- */ @@ -1370,7 +1365,7 @@ static void __init baycom_epp_dev_setup(struct net_device *dev) /* * initialize part of the device struct */ - dev->init = baycom_probe; + baycom_probe(dev); } static int __init init_baycomepp(void) diff --git a/drivers/net/hamradio/dmascc.c b/drivers/net/hamradio/dmascc.c index 1c68cb00005d..e1222036f04e 100644 --- a/drivers/net/hamradio/dmascc.c +++ b/drivers/net/hamradio/dmascc.c @@ -242,7 +242,7 @@ struct scc_priv { 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 @@ static void __exit dmascc_exit(void) { 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 @@ static int __init dmascc_init(void) { 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); + + 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); - /* Start timer */ - outb(1, tmr_base + TMR_CNT1); - outb(0, tmr_base + TMR_CNT1); + /* Start IRQ auto-detection */ + irqs = probe_irq_on(); - /* Wait and detect IRQ */ - time = jiffies; while (jiffies - time < 2 + HZ / TMR_0_HZ); - irq = probe_irq_off(irqs); + /* 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); + } - /* 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); - } + /* Start timer */ + outb(1, tmr_base + TMR_CNT1); + outb(0, tmr_base + TMR_CNT1); - 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; - } + /* Wait and detect IRQ */ + time = jiffies; while (jiffies - time < 2 + HZ / TMR_0_HZ); + irq = probe_irq_off(irqs); - /* 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(); - } + /* 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; + } - 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; + /* 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; + +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 --git a/drivers/net/hp-plus.c b/drivers/net/hp-plus.c index 7c9723158296..614ee7eb8ff5 100644 --- a/drivers/net/hp-plus.c +++ b/drivers/net/hp-plus.c @@ -140,12 +140,11 @@ static void cleanup_card(struct net_device *dev) { /* NB: hpp_close() handles free_irq */ release_region(dev->base_addr - NIC_OFFSET, HP_IO_EXTENT); - kfree(dev->priv); } struct net_device * __init hp_plus_probe(int unit) { - struct net_device *dev = alloc_etherdev(0); + struct net_device *dev = alloc_ei_netdev(); int err; if (!dev) @@ -154,8 +153,6 @@ struct net_device * __init hp_plus_probe(int unit) sprintf(dev->name, "eth%d", unit); netdev_boot_setup_check(dev); - dev->priv = NULL; /* until all 8390-based use alloc_etherdev() */ - err = do_hpp_probe(dev); if (err) goto out; @@ -215,13 +212,6 @@ static int __init hpp_probe1(struct net_device *dev, int ioaddr) 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); { @@ -460,10 +450,9 @@ init_module(void) if (this_dev != 0) break; /* only autoprobe 1st one */ printk(KERN_NOTICE "hp-plus.c: Presently autoprobing (not recommended) for a single card.\n"); } - dev = alloc_etherdev(0); + dev = alloc_ei_netdev(); if (!dev) break; - dev->priv = NULL; dev->irq = irq[this_dev]; dev->base_addr = io[this_dev]; if (do_hpp_probe(dev) == 0) { diff --git a/drivers/net/hp.c b/drivers/net/hp.c index cc665440203d..bc50724df3ac 100644 --- a/drivers/net/hp.c +++ b/drivers/net/hp.c @@ -104,12 +104,11 @@ static void cleanup_card(struct net_device *dev) { free_irq(dev->irq, dev); release_region(dev->base_addr - NIC_OFFSET, HP_IO_EXTENT); - kfree(dev->priv); } struct net_device * __init hp_probe(int unit) { - struct net_device *dev = alloc_etherdev(0); + struct net_device *dev = alloc_ei_netdev(); int err; if (!dev) @@ -118,8 +117,6 @@ struct net_device * __init hp_probe(int unit) sprintf(dev->name, "eth%d", unit); netdev_boot_setup_check(dev); - dev->priv = NULL; /* until all 8390-based use alloc_etherdev() */ - err = do_hp_probe(dev); if (err) goto out; @@ -167,13 +164,6 @@ static int __init hp_probe1(struct net_device *dev, int ioaddr) 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++) @@ -202,14 +192,14 @@ static int __init hp_probe1(struct net_device *dev, int ioaddr) 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; } } @@ -231,9 +221,6 @@ static int __init hp_probe1(struct net_device *dev, int ioaddr) hp_init_card(dev); return 0; -out1: - kfree(dev->priv); - dev->priv = NULL; out: release_region(ioaddr, HP_IO_EXTENT); return retval; @@ -432,10 +419,9 @@ init_module(void) if (this_dev != 0) break; /* only autoprobe 1st one */ printk(KERN_NOTICE "hp.c: Presently autoprobing (not recommended) for a single card.\n"); } - dev = alloc_etherdev(0); + dev = alloc_ei_netdev(); if (!dev) break; - dev->priv = NULL; dev->irq = irq[this_dev]; dev->base_addr = io[this_dev]; if (do_hp_probe(dev) == 0) { diff --git a/drivers/net/hydra.c b/drivers/net/hydra.c index 921677364943..3a2ec0a71830 100644 --- a/drivers/net/hydra.c +++ b/drivers/net/hydra.c @@ -96,10 +96,9 @@ static int __init hydra_init(unsigned long board) 0x10, 0x12, 0x14, 0x16, 0x18, 0x1a, 0x1c, 0x1e, }; - dev = alloc_etherdev(0); + dev = alloc_ei_netdev(); if (!dev) return -ENOMEM; - dev->priv = NULL; SET_MODULE_OWNER(dev); for(j = 0; j < ETHER_ADDR_LEN; j++) @@ -120,14 +119,6 @@ static int __init hydra_init(unsigned long board) 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"); - free_irq(IRQ_AMIGA_PORTS, dev); - free_netdev(dev); - 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), dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2], dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]); @@ -157,7 +148,6 @@ static int __init hydra_init(unsigned long board) return 0; free_irq(IRQ_AMIGA_PORTS, dev); - kfree(dev->priv); free_netdev(dev); return err; } diff --git a/drivers/net/ibmlana.c b/drivers/net/ibmlana.c index 934335ce35e7..9fb3c99645fa 100644 --- a/drivers/net/ibmlana.c +++ b/drivers/net/ibmlana.c @@ -906,7 +906,7 @@ static void ibmlana_set_multicast_list(struct net_device *dev) 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 @@ int ibmlana_probe(struct net_device *dev) 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 @@ int ibmlana_probe(struct net_device *dev) 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 @@ int ibmlana_probe(struct net_device *dev) 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 @@ int ibmlana_probe(struct net_device *dev) #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 @@ MODULE_LICENSE("GPL"); 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 --git a/drivers/net/ibmlana.h b/drivers/net/ibmlana.h index 17ce22ef9f49..1b535e8441cc 100644 --- a/drivers/net/ibmlana.h +++ b/drivers/net/ibmlana.h @@ -275,7 +275,4 @@ typedef struct { #endif /* _IBM_LANA_DRIVER_ */ -extern int ibmlana_probe(struct net_device *); - - #endif /* _IBM_LANA_INCLUDE_ */ diff --git a/drivers/net/irda/sa1100_ir.c b/drivers/net/irda/sa1100_ir.c index 58e931268c04..c4b7b2a27e7c 100644 --- a/drivers/net/irda/sa1100_ir.c +++ b/drivers/net/irda/sa1100_ir.c @@ -20,6 +20,7 @@ */ #include <linux/config.h> #include <linux/module.h> +#include <linux/moduleparam.h> #include <linux/types.h> #include <linux/init.h> #include <linux/errno.h> @@ -358,9 +359,13 @@ static void sa1100_irda_shutdown(struct sa1100_irda *si) 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_suspend(struct device *_dev, u32 state, u32 level) 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 @@ static int sa1100_irda_start(struct net_device *dev) 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_tx_dma: err_rx_dma: free_irq(dev->irq, dev); err_irq: - MOD_DEC_USE_COUNT; return err; } @@ -930,8 +936,6 @@ static int sa1100_irda_stop(struct net_device *dev) sa1100_set_power(si, 0); - MOD_DEC_USE_COUNT; - return 0; } @@ -947,56 +951,48 @@ static int sa1100_irda_init_iobuf(iobuff_t *io, int size) 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 @@ static int sa1100_irda_net_init(struct net_device *dev) 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; + if (dev) { + struct sa1100_irda *si = dev->priv; + unregister_netdev(dev); + kfree(si->tx_buff.head); + kfree(si->rx_buff.head); + free_netdev(dev); + } - kfree(si->tx_buff.head); - kfree(si->rx_buff.head); - kfree(si); + 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 @@ static int __init sa1100_irda_init(void) 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); - } - 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); + ret = driver_register(&sa1100ir_driver); + if (ret == 0) { + ret = platform_device_register(&sa1100ir_device); + if (ret) + driver_unregister(&sa1100ir_driver); } -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 <rmk@arm.linux.org.uk>"); 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 --git a/drivers/net/ixgb/ixgb_main.c b/drivers/net/ixgb/ixgb_main.c index 7b72cf31f9d1..ab0f3afb0b4a 100644 --- a/drivers/net/ixgb/ixgb_main.c +++ b/drivers/net/ixgb/ixgb_main.c @@ -446,7 +446,7 @@ ixgb_probe(struct pci_dev *pdev, const struct pci_device_id *ent) iounmap(adapter->hw.hw_addr); err_ioremap: pci_release_regions(pdev); - kfree(netdev); + free_netdev(netdev); err_alloc_etherdev: return -ENOMEM; } diff --git a/drivers/net/lne390.c b/drivers/net/lne390.c index 217ef36678b9..d6dfa79888af 100644 --- a/drivers/net/lne390.c +++ b/drivers/net/lne390.c @@ -149,12 +149,11 @@ static void cleanup_card(struct net_device *dev) release_region(dev->base_addr, LNE390_IO_EXTENT); if (ei_status.reg0) iounmap((void *)dev->mem_start); - kfree(dev->priv); } struct net_device * __init lne390_probe(int unit) { - struct net_device *dev = alloc_etherdev(0); + struct net_device *dev = alloc_ei_netdev(); int err; if (!dev) @@ -163,8 +162,6 @@ struct net_device * __init lne390_probe(int unit) sprintf(dev->name, "eth%d", unit); netdev_boot_setup_check(dev); - dev->priv = NULL; /* until all 8390-based use alloc_etherdev() */ - err = do_lne390_probe(dev); if (err) goto out; @@ -213,11 +210,6 @@ static int __init lne390_probe1(struct net_device *dev, int ioaddr) 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++) @@ -238,8 +230,6 @@ static int __init lne390_probe1(struct net_device *dev, int ioaddr) 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; } @@ -313,8 +303,6 @@ static int __init lne390_probe1(struct net_device *dev, int ioaddr) return 0; cleanup: free_irq(dev->irq, dev); - kfree(dev->priv); - dev->priv = NULL; return ret; } @@ -434,10 +422,9 @@ int init_module(void) for (this_dev = 0; this_dev < MAX_LNE_CARDS; this_dev++) { if (io[this_dev] == 0 && this_dev != 0) break; - dev = alloc_etherdev(0); + dev = alloc_ei_netdev(); if (!dev) break; - dev->priv = NULL; dev->irq = irq[this_dev]; dev->base_addr = io[this_dev]; dev->mem_start = mem[this_dev]; diff --git a/drivers/net/lp486e.c b/drivers/net/lp486e.c index 3e687d9cbd41..7dda5dd054c8 100644 --- a/drivers/net/lp486e.c +++ b/drivers/net/lp486e.c @@ -1314,18 +1314,23 @@ static int io = IOADDR; 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 --git a/drivers/net/mac8390.c b/drivers/net/mac8390.c index 930b54471d91..36bbd4fde373 100644 --- a/drivers/net/mac8390.c +++ b/drivers/net/mac8390.c @@ -228,12 +228,12 @@ struct net_device * __init mac8390_probe(int unit) volatile unsigned short *i; int version_disp = 0; struct nubus_dev * ndev = NULL; - static int probed; - int err = -ENDOEV; + int err = -ENODEV; struct nubus_dir dir; struct nubus_dirent ent; int offset; + static unsigned int slots; enum mac8390_type cardtype; @@ -242,10 +242,9 @@ struct net_device * __init mac8390_probe(int unit) if (!MACH_IS_MAC) return ERR_PTR(-ENODEV); - dev = alloc_etherdev(0); + dev = alloc_ei_netdev(); if (!dev) return ERR_PTR(-ENOMEM); - dev->priv = NULL; if (unit >= 0) sprintf(dev->name, "eth%d", unit); @@ -371,15 +370,12 @@ struct net_device * __init mac8390_probe(int unit) goto out; err = register_netdev(dev); if (err) - goto out1; + goto out; return dev; -out1: - kfree(dev->priv); - dev->priv = NULL; out: free_netdev(dev); - return ERR_PTE(err); + return ERR_PTR(err); } #ifdef MODULE @@ -412,7 +408,6 @@ void cleanup_module(void) struct net_device *dev = dev_mac890[i]; if (dev) { unregister_netdev(dev); - kfree(dev->priv); free_netdev(dev); } } @@ -444,12 +439,6 @@ static int __init mac8390_initdev(struct net_device * dev, struct nubus_dev * nd 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; @@ -520,8 +509,6 @@ static int __init mac8390_initdev(struct net_device * dev, struct nubus_dev * nd break; default: printk(KERN_ERR "Card type %s is unsupported, sorry\n", cardname[type]); - kfree(dev->priv); - dev->priv = NULL; return -ENODEV; } diff --git a/drivers/net/macmace.c b/drivers/net/macmace.c index b8efd1fc5269..79a6fc139757 100644 --- a/drivers/net/macmace.c +++ b/drivers/net/macmace.c @@ -229,7 +229,7 @@ struct net_device *mace_probe(int unit) if (checksum != 0xFF) { free_netdev(dev); - return -ENODEV; + return ERR_PTR(-ENODEV); } memset(&mp->stats, 0, sizeof(mp->stats)); diff --git a/drivers/net/macsonic.c b/drivers/net/macsonic.c index 316e66f65acf..73b1bbe3861c 100644 --- a/drivers/net/macsonic.c +++ b/drivers/net/macsonic.c @@ -495,7 +495,6 @@ int __init mac_nubus_sonic_probe(struct net_device* dev) { static int slots; struct nubus_dev* ndev = NULL; - struct sonic_local* lp; unsigned long base_addr, prom_addr; u16 sonic_dcr; int id; diff --git a/drivers/net/meth.c b/drivers/net/meth.c index 3a253f16cb88..17524d261b1a 100644 --- a/drivers/net/meth.c +++ b/drivers/net/meth.c @@ -95,7 +95,6 @@ typedef struct meth_private { 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 @@ struct net_device_stats *meth_stats(struct net_device *dev) /* * 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 @@ int meth_init(struct net_device *dev) 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 @@ int meth_init(struct net_device *dev) 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 @@ struct net_device meth_devs[1] = { 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 --git a/drivers/net/mvme147.c b/drivers/net/mvme147.c index 60dd4689f887..5995658b18fb 100644 --- a/drivers/net/mvme147.c +++ b/drivers/net/mvme147.c @@ -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 @@ -68,6 +68,7 @@ struct net_device * __init mvme147lance_probe(int unit) struct m147lance_private *lp; u_long *addr; u_long address; + int err; if (!MACH_IS_MVME147 || called) return ERR_PTR(-ENODEV); @@ -112,7 +113,7 @@ struct net_device * __init mvme147lance_probe(int unit) 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); diff --git a/drivers/net/ne.c b/drivers/net/ne.c index 77ccefbf7758..e9edd5623085 100644 --- a/drivers/net/ne.c +++ b/drivers/net/ne.c @@ -194,18 +194,16 @@ static int __init do_ne_probe(struct net_device *dev) static void cleanup_card(struct net_device *dev) { - 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); - kfree(priv); } struct net_device * __init ne_probe(int unit) { - struct net_device *dev = alloc_etherdev(0); + struct net_device *dev = alloc_ei_netdev(); int err; if (!dev) @@ -214,8 +212,6 @@ struct net_device * __init ne_probe(int unit) sprintf(dev->name, "eth%d", unit); netdev_boot_setup_check(dev); - dev->priv = NULL; /* until all 8390-based use alloc_etherdev() */ - err = do_ne_probe(dev); if (err) goto out; @@ -464,20 +460,12 @@ static int __init ne_probe1(struct net_device *dev, int ioaddr) 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; @@ -511,9 +499,6 @@ static int __init ne_probe1(struct net_device *dev, int ioaddr) 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; @@ -797,10 +782,9 @@ int init_module(void) int this_dev, found = 0; for (this_dev = 0; this_dev < MAX_NE_CARDS; this_dev++) { - struct net_device *dev = alloc_etherdev(0); + struct net_device *dev = alloc_ei_netdev(); if (!dev) break; - dev->priv = NULL; dev->irq = irq[this_dev]; dev->mem_end = bad[this_dev]; dev->base_addr = io[this_dev]; diff --git a/drivers/net/ne2.c b/drivers/net/ne2.c index 54bbbd82780a..549741aad7bc 100644 --- a/drivers/net/ne2.c +++ b/drivers/net/ne2.c @@ -280,14 +280,13 @@ static void cleanup_card(struct net_device *dev) { 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 * __init ne2_probe(int unit) { - struct net_device *dev = alloc_etherdev(0); + struct net_device *dev = alloc_ei_netdev(); int err; if (!dev) @@ -296,8 +295,6 @@ struct net_device * __init ne2_probe(int unit) sprintf(dev->name, "eth%d", unit); netdev_boot_setup_check(dev); - dev->priv = NULL; /* until all 8390-based use alloc_etherdev() */ - err = do_ne2_probe(dev); if (err) goto out; @@ -482,14 +479,6 @@ static int __init ne2_probe1(struct net_device *dev, int slot) 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]; @@ -797,10 +786,9 @@ int init_module(void) int this_dev, found = 0; for (this_dev = 0; this_dev < MAX_NE_CARDS; this_dev++) { - dev = alloc_etherdev(0); + dev = alloc_ei_netdev(); if (!dev) break; - dev->priv = NULL; dev->irq = irq[this_dev]; dev->mem_end = bad[this_dev]; dev->base_addr = io[this_dev]; diff --git a/drivers/net/ne2k_cbus.c b/drivers/net/ne2k_cbus.c index 9d70f5d724ae..d0f3ca565384 100644 --- a/drivers/net/ne2k_cbus.c +++ b/drivers/net/ne2k_cbus.c @@ -189,7 +189,7 @@ static void cleanup_card(struct net_device *dev) struct net_device * __init ne_probe(int unit) { - struct net_device *dev = alloc_etherdev(0); + struct net_device *dev = alloc_ei_netdev(); int err; if (!dev) @@ -198,8 +198,6 @@ struct net_device * __init ne_probe(int unit) sprintf(dev->name, "eth%d", unit); netdev_boot_setup_check(dev); - dev->priv = NULL; /* until all 8390-based use alloc_etherdev() */ - err = do_ne_probe(dev); if (err) goto out; @@ -500,14 +498,6 @@ static int __init ne_probe1(struct net_device *dev, int ioaddr) 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); @@ -849,10 +839,9 @@ int init_module(void) int this_dev, found = 0; for (this_dev = 0; this_dev < MAX_NE_CARDS; this_dev++) { - struct net_device *dev = alloc_etherdev(0); + struct net_device *dev = alloc_ei_netdev(); if (!dev) break; - dev->priv = NULL; dev->irq = irq[this_dev]; dev->mem_end = bad[this_dev]; dev->base_addr = io[this_dev]; diff --git a/drivers/net/ne3210.c b/drivers/net/ne3210.c index 52f67cba916a..5d3aea794788 100644 --- a/drivers/net/ne3210.c +++ b/drivers/net/ne3210.c @@ -111,12 +111,6 @@ static int __init ne3210_eisa_probe (struct device *device) 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; @@ -357,24 +351,6 @@ static struct eisa_driver ne3210_eisa_driver = { }, }; -#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 --git a/drivers/net/net_init.c b/drivers/net/net_init.c index a61eac6cc10e..72bb389e0d34 100644 --- a/drivers/net/net_init.c +++ b/drivers/net/net_init.c @@ -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 --git a/drivers/net/ns83820.c b/drivers/net/ns83820.c index 3b57cbf2db7d..a525174f11f0 100644 --- a/drivers/net/ns83820.c +++ b/drivers/net/ns83820.c @@ -374,19 +374,6 @@ static int lnksts = 0; /* CFG_LNKSTS bit polarity */ #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 rx_info { struct ns83820 { - struct net_device net_dev; /* must be first */ struct net_device_stats stats; u8 *base; @@ -478,6 +464,29 @@ struct ns83820 { 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 @@ static inline int ns83820_add_rx_skb(struct ns83820 *dev, struct sk_buff *skb) 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; i<NR_RX_DESC; i++) { @@ -570,7 +580,7 @@ static inline int rx_refill(struct ns83820 *dev, int gfp) res &= 0xf; skb_reserve(skb, res); - skb->dev = &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 @@ static inline int rx_refill(struct ns83820 *dev, int gfp) 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 @@ static inline void clear_rx_desc(struct ns83820 *dev, unsigned i) 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 @@ static void phy_intr(struct ns83820 *dev) 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 @@ static int ns83820_setup_rx(struct ns83820 *dev) 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 @@ static int ns83820_setup_rx(struct ns83820 *dev) 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 @@ static int ns83820_setup_rx(struct ns83820 *dev) 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 ns83820_cleanup_rx(struct ns83820 *dev) } } -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 @@ static void rx_irq(struct ns83820 *dev) } 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 @@ out: 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 @@ static void rx_action(unsigned long _dev) 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 @@ static inline void kick_tx(struct ns83820 *dev) /* 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 @@ static void do_tx_done(struct ns83820 *dev) /* 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 @@ static void ns83820_cleanup_tx(struct ns83820 *dev) * 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 @@ static int ns83820_hard_start_xmit(struct sk_buff *skb, struct net_device *_dev) 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 @@ again: 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 @@ again: 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 @@ again: /* 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 @@ static void ns83820_update_stats(struct ns83820 *dev) 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 @@ static int ns83820_ethtool_ioctl (struct ns83820 *dev, void *useraddr) 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 @@ static void ns83820_mib_isr(struct ns83820 *dev) 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 @@ static void ns83820_do_isr(struct ns83820 *dev, u32 isr) 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 @@ static void ns83820_do_isr(struct ns83820 *dev, u32 isr) 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 @@ static void ns83820_do_isr(struct ns83820 *dev, u32 isr) 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 @@ static void ns83820_do_isr(struct ns83820 *dev, u32 isr) * 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 @@ static void ns83820_do_isr(struct ns83820 *dev, u32 isr) /* 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 @@ static void ns83820_do_reset(struct ns83820 *dev, u32 which) 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 @@ static int ns83820_stop(struct net_device *_dev) 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 @@ static void ns83820_tx_timeout(struct net_device *_dev) 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 @@ static void ns83820_tx_timeout(struct net_device *_dev) 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_timeout(struct net_device *_dev) 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 @@ static void ns83820_tx_watch(unsigned long data) ); #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 @@ static int ns83820_open(struct net_device *_dev) writel(0, dev->base + PQCR); - ret = ns83820_setup_rx(dev); + ret = ns83820_setup_rx(ndev); if (ret) goto failed; @@ -1481,16 +1500,16 @@ static int ns83820_open(struct net_device *_dev) 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 void ns83820_getmac(struct ns83820 *dev, u8 *mac) } } -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 @@ static void ns83820_set_multicast(struct net_device *_dev) 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 @@ static void ns83820_run_bist(struct ns83820 *dev, const char *name, u32 enable, 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 @@ static unsigned ns83820_mii_write_reg(struct ns83820 *dev, unsigned phy, unsigne 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 @@ static void ns83820_probe_phy(struct ns83820 *dev) 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 void ns83820_probe_phy(struct ns83820 *dev) 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 @@ static int __devinit ns83820_init_one(struct pci_dev *pci_dev, const struct pci_ 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 @@ static int __devinit ns83820_init_one(struct pci_dev *pci_dev, const struct pci_ 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 @@ static int __devinit ns83820_init_one(struct pci_dev *pci_dev, const struct pci_ 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 @@ static int __devinit ns83820_init_one(struct pci_dev *pci_dev, const struct pci_ /* 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 @@ static int __devinit ns83820_init_one(struct pci_dev *pci_dev, const struct pci_ 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 @@ static int __devinit ns83820_init_one(struct pci_dev *pci_dev, const struct pci_ /* 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 @@ out_disable: 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: - free_netdev(&dev->net_dev); + free_netdev(ndev); pci_set_drvdata(pci_dev, NULL); out: return err; @@ -2042,24 +2084,25 @@ out: 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 --git a/drivers/net/oaknet.c b/drivers/net/oaknet.c index c72a54c20b8b..afb0d29afbc3 100644 --- a/drivers/net/oaknet.c +++ b/drivers/net/oaknet.c @@ -106,10 +106,9 @@ static int __init oaknet_init(void) if (!ioaddr) return -ENOMEM; - dev = alloc_etherdev(0); + dev = alloc_ei_netdev(); if (!dev) goto out_unmap; - dev->priv = NULL; ret = -EBUSY; if (!request_region(OAKNET_IO_BASE, OAKNET_IO_SIZE, name)) @@ -152,14 +151,6 @@ static int __init oaknet_init(void) 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_region; - } - /* * Disable all chip interrupts for now and ACK all pending * interrupts. @@ -174,7 +165,7 @@ static int __init oaknet_init(void) 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. */ @@ -212,8 +203,6 @@ static int __init oaknet_init(void) out_irq; free_irq(dev->irq, dev); -out_priv: - kfree(dev->priv); out_region: release_region(OAKNET_IO_BASE, OAKNET_IO_SIZE); out_dev: @@ -660,20 +649,11 @@ oaknet_dma_error(struct net_device *dev, const char *name) */ 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; - unregister_netdev(oaknet_dev); - free_irq(oaknet_devs->irq, oaknet_devs); - kfree(priv); - release_region(ioaddr, OAKNET_IO_SIZE); - iounmap(ioaddr); - } - /* Convert to loop once driver supports multiple devices. */ + 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); } diff --git a/drivers/net/pcmcia/3c574_cs.c b/drivers/net/pcmcia/3c574_cs.c index e484a016392b..d7adba42c3b5 100644 --- a/drivers/net/pcmcia/3c574_cs.c +++ b/drivers/net/pcmcia/3c574_cs.c @@ -362,11 +362,8 @@ static void tc574_detach(dev_link_t *link) 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); @@ -554,21 +551,11 @@ static void tc574_release(dev_link_t *link) { 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); } /* @@ -1297,8 +1284,7 @@ static int el3_close(struct net_device *dev) link->open--; netif_stop_queue(dev); del_timer_sync(&lp->media); - if (link->state & DEV_STALE_CONFIG) - tc574_release(link); + return 0; } diff --git a/drivers/net/pcmcia/3c589_cs.c b/drivers/net/pcmcia/3c589_cs.c index 4339409895b2..5b38165f7fdd 100644 --- a/drivers/net/pcmcia/3c589_cs.c +++ b/drivers/net/pcmcia/3c589_cs.c @@ -276,11 +276,8 @@ static void tc589_detach(dev_link_t *link) 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); @@ -430,21 +427,11 @@ static void tc589_release(dev_link_t *link) { 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); } /*====================================================================== @@ -1073,8 +1060,6 @@ static int el3_close(struct net_device *dev) link->open--; netif_stop_queue(dev); del_timer_sync(&lp->media); - if (link->state & DEV_STALE_CONFIG) - tc589_release(link); return 0; } diff --git a/drivers/net/pcmcia/axnet_cs.c b/drivers/net/pcmcia/axnet_cs.c index 4c99ae63c41f..8ef57bdd7776 100644 --- a/drivers/net/pcmcia/axnet_cs.c +++ b/drivers/net/pcmcia/axnet_cs.c @@ -119,7 +119,7 @@ static void axnet_detach(dev_link_t *); 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 @@ static irqreturn_t ax_interrupt(int irq, void *dev_id, struct pt_regs *regs); /*====================================================================*/ 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 @@ typedef struct axnet_dev_t { 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 @@ static dev_link_t *axnet_attach(void) 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 @@ static dev_link_t *axnet_attach(void) 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 dev_link_t *axnet_attach(void) 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 @@ static void axnet_detach(dev_link_t *link) 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 int try_io_port(dev_link_t *link) 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 @@ static void axnet_config(dev_link_t *link) 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 @@ static void axnet_config(dev_link_t *link) 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 @@ static void axnet_config(dev_link_t *link) 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 @@ static void axnet_release(dev_link_t *link) { 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 @@ static int axnet_event(event_t event, int priority, 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 @@ static int axnet_event(event_t event, int priority, 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 @@ static int axnet_event(event_t event, int priority, 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 @@ static int axnet_event(event_t event, int priority, 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 void mdio_write(ioaddr_t addr, int phy_id, int loc, int value) 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 @@ static int axnet_open(struct net_device *dev) 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_open(struct net_device *dev) 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 @@ static int axnet_close(struct net_device *dev) 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 void axnet_reset_8390(struct net_device *dev) 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 struct ethtool_ops netdev_ethtool_ops = { 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 void do_set_multicast_list(struct net_device *dev); 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 @@ static int ax_open(struct net_device *dev) 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 @@ int ax_close(struct net_device *dev) 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 @@ void ei_tx_timeout(struct net_device *dev) 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 @@ static irqreturn_t ax_interrupt(int irq, void *dev_id, struct pt_regs * regs) } 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 irqreturn_t ax_interrupt(int irq, void *dev_id, struct pt_regs * regs) 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_err(struct net_device *dev) 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_tx_intr(struct net_device *dev) 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 @@ static void ei_rx_overrun(struct net_device *dev) 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 void ei_rx_overrun(struct net_device *dev) 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 @@ static void set_multicast_list(struct net_device *dev) } /** - * 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 int axdev_init(struct net_device *dev) 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 @@ static void NS8390_trigger_send(struct net_device *dev, unsigned int length, 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 --git a/drivers/net/pcmcia/com20020_cs.c b/drivers/net/pcmcia/com20020_cs.c index bdba5c911589..0a2bf4067cc4 100644 --- a/drivers/net/pcmcia/com20020_cs.c +++ b/drivers/net/pcmcia/com20020_cs.c @@ -145,20 +145,6 @@ typedef struct com20020_dev_t { 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 @@ static dev_link_t *com20020_attach(void) 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 @@ static void com20020_detach(dev_link_t *link) 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 @@ static void com20020_detach(dev_link_t *link) if (netif_running(dev)) dev->stop(dev); + + unregister_netdev(dev); /* * this is necessary because we register our IRQ separately @@ -300,10 +292,7 @@ static void com20020_detach(dev_link_t *link) */ 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 @@ static void com20020_release(dev_link_t *link) 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 --git a/drivers/net/pcmcia/fmvj18x_cs.c b/drivers/net/pcmcia/fmvj18x_cs.c index 9f5c60f1db11..b3d3e2c75ca0 100644 --- a/drivers/net/pcmcia/fmvj18x_cs.c +++ b/drivers/net/pcmcia/fmvj18x_cs.c @@ -332,11 +332,8 @@ static void fmvj18x_detach(dev_link_t *link) 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) @@ -720,17 +717,6 @@ static void fmvj18x_release(dev_link_t *link) 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); @@ -738,9 +724,6 @@ static void fmvj18x_release(dev_link_t *link) pcmcia_release_irq(link->handle, &link->irq); link->state &= ~DEV_CONFIG; - - if (link->state & DEV_STALE_CONFIG) - fmvj18x_detach(link); } /*====================================================================*/ @@ -1248,8 +1231,6 @@ static int fjn_close(struct net_device *dev) outb(INTR_OFF, ioaddr + LAN_CTRL); link->open--; - if (link->state & DEV_STALE_CONFIG) - fmvj18x_release(link); return 0; } /* fjn_close */ diff --git a/drivers/net/pcmcia/ibmtr_cs.c b/drivers/net/pcmcia/ibmtr_cs.c index 7a0c9c71dc2a..a5047f769369 100644 --- a/drivers/net/pcmcia/ibmtr_cs.c +++ b/drivers/net/pcmcia/ibmtr_cs.c @@ -125,8 +125,7 @@ static void ibmtr_detach(dev_link_t *); 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 @@ static dev_link_t *ibmtr_attach(void) 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 @@ static void ibmtr_detach(dev_link_t *link) 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 @@ static void ibmtr_config(dev_link_t *link) 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 @@ static void ibmtr_release(dev_link_t *link) 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 @@ static void ibmtr_release(dev_link_t *link) } link->state &= ~DEV_CONFIG; - - if (link->state & DEV_STALE_CONFIG) - ibmtr_detach(link); } /*====================================================================== @@ -482,7 +470,7 @@ static int ibmtr_event(event_t event, int priority, 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 --git a/drivers/net/pcmcia/nmclan_cs.c b/drivers/net/pcmcia/nmclan_cs.c index fc3c850545a9..e76bdf11a7bf 100644 --- a/drivers/net/pcmcia/nmclan_cs.c +++ b/drivers/net/pcmcia/nmclan_cs.c @@ -551,11 +551,8 @@ static void nmclan_detach(dev_link_t *link) 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); @@ -809,21 +806,11 @@ static void nmclan_release(dev_link_t *link) 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); } /* ---------------------------------------------------------------------------- @@ -990,8 +977,6 @@ static int mace_close(struct net_device *dev) link->open--; netif_stop_queue(dev); - if (link->state & DEV_STALE_CONFIG) - nmclan_release(link); return 0; } /* mace_close */ diff --git a/drivers/net/pcmcia/pcnet_cs.c b/drivers/net/pcmcia/pcnet_cs.c index 9d7c0b549f39..ca2fc0207067 100644 --- a/drivers/net/pcmcia/pcnet_cs.c +++ b/drivers/net/pcmcia/pcnet_cs.c @@ -224,7 +224,6 @@ static hw_info_t dl10019_info = { 0, 0, 0, 0, IS_DL10019|HAS_MII }; 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 @@ typedef struct pcnet_dev_t { 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 @@ static dev_link_t *pcnet_attach(void) 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 @@ static dev_link_t *pcnet_attach(void) 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 dev_link_t *pcnet_attach(void) 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 @@ static void pcnet_detach(dev_link_t *link) 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 int try_io_port(dev_link_t *link) 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 @@ failed: 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 @@ static void pcnet_release(dev_link_t *link) pcmcia_release_irq(link->handle, &link->irq); link->state &= ~DEV_CONFIG; - - if (link->state & DEV_STALE_CONFIG) - pcnet_detach(link); } /*====================================================================== @@ -820,7 +795,7 @@ static int pcnet_event(event_t event, int priority, 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 @@ static int pcnet_event(event_t event, int priority, 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 @@ static int pcnet_event(event_t event, int priority, 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 @@ static int pcnet_event(event_t event, int priority, 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 write_asic(ioaddr_t ioaddr, int location, short asic_data) 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 set_misc_reg(struct net_device *dev) 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 void mii_phy_probe(struct net_device *dev) 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 @@ static int pcnet_open(struct net_device *dev) 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_open(struct net_device *dev) 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 @@ static int pcnet_close(struct net_device *dev) 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 void pcnet_reset_8390(struct net_device *dev) 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 int set_config(struct net_device *dev, struct ifmap *map) 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 irqreturn_t ei_irq_wrapper(int irq, void *dev_id, struct pt_regs *regs) 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 struct ethtool_ops netdev_ethtool_ops = { 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 @@ static void dma_block_output(struct net_device *dev, int count, 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 @@ static int setup_shmem_window(dev_link_t *link, int start_pg, 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 --git a/drivers/net/pcmcia/smc91c92_cs.c b/drivers/net/pcmcia/smc91c92_cs.c index 20afb9b6cdda..2ffb11eda974 100644 --- a/drivers/net/pcmcia/smc91c92_cs.c +++ b/drivers/net/pcmcia/smc91c92_cs.c @@ -411,11 +411,8 @@ static void smc91c92_detach(dev_link_t *link) 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); @@ -1067,13 +1064,6 @@ static void smc91c92_release(dev_link_t *link) 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); @@ -1085,9 +1075,6 @@ static void smc91c92_release(dev_link_t *link) } link->state &= ~DEV_CONFIG; - - if (link->state & DEV_STALE_CONFIG) - smc91c92_detach(link); } /*====================================================================== @@ -1313,8 +1300,6 @@ static int smc_close(struct net_device *dev) link->open--; del_timer_sync(&smc->media); - if (link->state & DEV_STALE_CONFIG) - smc91c92_release(link); return 0; } /* smc_close */ diff --git a/drivers/net/pcnet32.c b/drivers/net/pcnet32.c index 950157166c96..14118618f11e 100644 --- a/drivers/net/pcnet32.c +++ b/drivers/net/pcnet32.c @@ -806,11 +806,12 @@ pcnet32_probe1(unsigned long ioaddr, unsigned int irq_line, int shared, dev->tx_timeout = pcnet32_tx_timeout; dev->watchdog_timeo = (5*HZ); + /* 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 --git a/drivers/net/plip.c b/drivers/net/plip.c index 83236666372c..64a1df7c2702 100644 --- a/drivers/net/plip.c +++ b/drivers/net/plip.c @@ -277,19 +277,11 @@ inline static unsigned char read_status (struct net_device *dev) 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 @@ plip_init_netdev(struct net_device *dev) INIT_WORK(&nl->timer, (void (*)(void *))plip_timer_bh, dev); spin_lock_init(&nl->lock); - - return 0; } /* Bottom half handler for the delayed request. @@ -1289,7 +1279,6 @@ static void plip_attach (struct parport *port) } strcpy(dev->name, name); - dev->init = plip_init_netdev; SET_MODULE_OWNER(dev); dev->irq = port->irq; @@ -1310,10 +1299,22 @@ static void plip_attach (struct parport *port) return; } + plip_init_netdev(dev); + if (register_netdev(dev)) { printk(KERN_ERR "%s: network register failed\n", name); 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; diff --git a/drivers/net/ppp_generic.c b/drivers/net/ppp_generic.c index dc9289503534..e335aa8cb386 100644 --- a/drivers/net/ppp_generic.c +++ b/drivers/net/ppp_generic.c @@ -917,19 +917,14 @@ ppp_net_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) 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 @@ ppp_create_interface(int unit, int *retp) 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_create_interface(int unit, int *retp) 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 @@ ppp_create_interface(int unit, int *retp) *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 @@ static void ppp_shutdown_interface(struct ppp *ppp) 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 --git a/drivers/net/sk98lin/skge.c b/drivers/net/sk98lin/skge.c index 6cfa52b5604d..17d858e98b87 100644 --- a/drivers/net/sk98lin/skge.c +++ b/drivers/net/sk98lin/skge.c @@ -837,7 +837,7 @@ SK_EVPARA EvPara; 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 --git a/drivers/net/skfp/skfddi.c b/drivers/net/skfp/skfddi.c index 5482c82c1734..a7345c4ee273 100644 --- a/drivers/net/skfp/skfddi.c +++ b/drivers/net/skfp/skfddi.c @@ -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 <bellucda@tiscali.it> + * 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 @@ static const char *boot_msg = #include <linux/module.h> #include <linux/kernel.h> -#include <linux/string.h> -#include <linux/ptrace.h> #include <linux/errno.h> #include <linux/ioport.h> #include <linux/slab.h> #include <linux/interrupt.h> #include <linux/pci.h> -#include <linux/delay.h> -#include <linux/ctype.h> // isdigit #include <linux/netdevice.h> #include <linux/fddidevice.h> #include <linux/skbuff.h> @@ -106,17 +97,7 @@ static const char *boot_msg = #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 @@ MODULE_AUTHOR("Mirko Lindner <mlindner@syskonnect.de>"); // 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 @@ static int loading_module; #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 @@ static int loading_module; * 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 @@ static int loading_module; * 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; - - 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("%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; - -#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 */ - - 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; - } -#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); + u32 port, len; + int err; - port = (unsigned long)ioremap(port, 0x4000); - if (!port){ - printk("skfp: Unable to map MEMORY register, " - "FDDI adapter will be disabled.\n"); - break; - } -#endif + PRINTK(KERN_INFO "entering skfp_init_one\n"); - 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 (num_boards == 0) + printk("%s\n", boot_msg); - } - - } // if (dev != NULL) + err = pci_enable_device(pdev); + if (err) + goto err_out1; - } // 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); +#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; } -} // skfp_probe - + port = pci_resource_start(pdev, 0); + len = pci_resource_len(pdev, 0); -/************************ - * - * 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; + if (len < 0x4000) { + printk(KERN_ERR "skfp: Invalid PCI region size: %d\n", 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; +#else + if (!(pci_resource_flags(pdev, 1) & IO_RESOURCE_IO)) { + printk(KERN_ERR "skfp: region is not PIO resource\n"); + err = -EIO; + goto err_out1; } - 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); + + 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; } - 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; } - 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); +#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; + } +#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 + /* 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; +} -/************************ - * - * 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 *)) +/* + * Called for each adapter board from pci_unregister_driver + */ +static void __devexit skfp_remove_one(struct pci_dev *pdev) { - 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 + struct net_device *p = pci_get_drvdata(pdev); + struct s_smc *lp = p->priv; + unregister_netdev(p); -/************************ - * - * 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; + if (lp->os.SharedMemAddr) { + pci_free_consistent(&lp->os.pdev, + lp->os.SharedMemSize, + lp->os.SharedMemAddr, + lp->os.SharedMemDMA); + lp->os.SharedMemAddr = NULL; } - return i; -} // fddi_dev_index - - -/************************ - * - * 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) -{ - struct net_device *p = dev; - - if (p) { - while (((struct s_smc *) (p->priv))->os.next_module) { - p = ((struct s_smc *) (p->priv))->os.next_module; - } - - 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.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 @@ static void link_modules(struct net_device *dev, struct net_device *tmp) * 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 @@ static int skfp_driver_init(struct net_device *dev) 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 @@ fail: bp->LocalRxBuffer, bp->LocalRxBufferDMA); bp->LocalRxBuffer = NULL; } - return (-1); + return err; } // skfp_driver_init @@ -766,14 +519,15 @@ fail: 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 @@ static int skfp_open(struct net_device *dev) /* 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_open(struct net_device *dev) 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 @@ static int skfp_close(struct net_device *dev) /* 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 @@ static int skfp_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) break; default: printk("ioctl for %s: unknow cmd: %04x\n", dev->name, ioc.cmd); + status = -EOPNOTSUPP; + } // switch return status; @@ -2538,63 +2289,21 @@ void drv_reset_indication(struct s_smc *smc) } // 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 --git a/drivers/net/smc-mca.c b/drivers/net/smc-mca.c index b9dc4a31700e..c2e153a85238 100644 --- a/drivers/net/smc-mca.c +++ b/drivers/net/smc-mca.c @@ -202,22 +202,18 @@ int __init ultramca_probe(struct device *gen_dev) 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 @@ int __init ultramca_probe(struct device *gen_dev) /* 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 @@ int __init ultramca_probe(struct device *gen_dev) 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 @@ -339,13 +327,16 @@ int __init ultramca_probe(struct device *gen_dev) 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 +454,14 @@ static int ultramca_remove(struct device *gen_dev) 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 --git a/drivers/net/smc-ultra.c b/drivers/net/smc-ultra.c index 8692ce982dae..27880adda1eb 100644 --- a/drivers/net/smc-ultra.c +++ b/drivers/net/smc-ultra.c @@ -165,12 +165,11 @@ static void cleanup_card(struct net_device *dev) pnp_device_detach(idev); #endif release_region(dev->base_addr - ULTRA_NIC_OFFSET, ULTRA_IO_EXTENT); - kfree(dev->priv); } struct net_device * __init ultra_probe(int unit) { - struct net_device *dev = alloc_etherdev(0); + struct net_device *dev = alloc_ei_netdev(); int err; if (!dev) @@ -179,8 +178,6 @@ struct net_device * __init ultra_probe(int unit) sprintf(dev->name, "eth%d", unit); netdev_boot_setup_check(dev); - dev->priv = NULL; /* until all 8390-based use alloc_etherdev() */ - err = do_ultra_probe(dev); if (err) goto out; @@ -267,13 +264,6 @@ static int __init ultra_probe1(struct net_device *dev, int ioaddr) 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; @@ -565,10 +555,9 @@ init_module(void) if (this_dev != 0) break; /* only autoprobe 1st one */ printk(KERN_NOTICE "smc-ultra.c: Presently autoprobing (not recommended) for a single card.\n"); } - dev = alloc_etherdev(0); + dev = alloc_ei_netdev(); if (!dev) break; - dev->priv = NULL; dev->irq = irq[this_dev]; dev->base_addr = io[this_dev]; if (do_ultra_probe(dev) == 0) { diff --git a/drivers/net/smc-ultra32.c b/drivers/net/smc-ultra32.c index 8bfb162c820a..c400ef7db61e 100644 --- a/drivers/net/smc-ultra32.c +++ b/drivers/net/smc-ultra32.c @@ -102,7 +102,6 @@ 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); - kfree(dev->priv); } /* Probe for the Ultra32. This looks like a 8013 with the station @@ -120,7 +119,7 @@ struct net_device * __init ultra32_probe(int unit) if (!EISA_bus) return ERR_PTR(-ENODEV); - dev = alloc_etherdev(0); + dev = alloc_ei_netdev(); if (!dev) return ERR_PTR(-ENOMEM); @@ -243,13 +242,6 @@ static int __init ultra32_probe1(struct net_device *dev, int ioaddr) 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; diff --git a/drivers/net/stnic.c b/drivers/net/stnic.c index de00fe55796c..74a0707133dd 100644 --- a/drivers/net/stnic.c +++ b/drivers/net/stnic.c @@ -108,19 +108,10 @@ static int __init stnic_probe(void) return -ENODEV; /* New style probing API */ - dev = alloc_etherdev(0); + dev = alloc_ei_netdev(); if (!dev) return -ENOMEM; SET_MODULE_OWNER(dev); - dev->priv = NULL; - - /* 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"); - free_netdev(dev); - return -ENOMEM; - } #ifdef CONFIG_SH_STANDARD_BIOS sh_bios_get_node_addr (stnic_eadr); @@ -139,7 +130,6 @@ static int __init stnic_probe(void) err = request_irq (dev->irq, ei_interrupt, 0, dev->name, dev); if (err) { printk (KERN_EMERG " unable to get IRQ %d.\n", dev->irq); - kfree(dev->priv); free_netdev(dev); return err; } @@ -165,7 +155,6 @@ static int __init stnic_probe(void) err = register_netdev(dev); if (err) { free_irq(dev->irq, dev); - kfree(dev->priv); free_netdev(dev); return err; } @@ -318,7 +307,6 @@ static void __exit stnic_cleanup(void) { unregister_netdev(stnic_dev); free_irq(stnic_dev->irq, stnic_dev); - kfree(stnic_dev->priv); free_netdev(stnic_dev); } diff --git a/drivers/net/sun3_82586.c b/drivers/net/sun3_82586.c index c9fa871bd7cb..669a02fb74e0 100644 --- a/drivers/net/sun3_82586.c +++ b/drivers/net/sun3_82586.c @@ -55,6 +55,7 @@ static int fifo=0x8; /* don't change */ #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;} @@ -298,7 +299,7 @@ struct net_device * __init sun3_82586_probe(int unit) 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; @@ -327,7 +328,7 @@ out2: out1: free_netdev(dev); out: - iounmap(ioaddr); + iounmap((void *)ioaddr); return ERR_PTR(err); } @@ -1163,8 +1164,8 @@ void cleanup_module(void) unsigned long ioaddr = dev_sun3_82586->base_addr; unregister_netdev(dev_sun3_82586); release_region(ioaddr, SUN3_82586_TOTAL_SIZE); - iounmap(ioaddr); - free_netdev(dev); + iounmap((void *)ioaddr); + free_netdev(dev_sun3_82586); } #endif /* MODULE */ diff --git a/drivers/net/sun3lance.c b/drivers/net/sun3lance.c index fb372e9fcf2a..f445f1f26d33 100644 --- a/drivers/net/sun3lance.c +++ b/drivers/net/sun3lance.c @@ -287,7 +287,7 @@ struct net_device * __init sun3lance_probe(int unit) out1: #ifdef CONFIG_SUN3 - iounmap(dev->base_addr); + iounmap((void *)dev->base_addr); #endif out: free_netdev(dev); @@ -327,7 +327,7 @@ static int __init lance_probe( struct net_device *dev) ioaddr_probe[1] = tmp2; #ifdef CONFIG_SUN3 - iounmap(ioaddr); + iounmap((void *)ioaddr); #endif return 0; } @@ -957,7 +957,7 @@ void cleanup_module(void) { unregister_netdev(sun3lance_dev); #ifdef CONFIG_SUN3 - iounmap(sun3lance_dev->base_addr); + iounmap((void *)sun3lance_dev->base_addr); #endif free_netdev(sun3lance_dev); } diff --git a/drivers/net/tokenring/3c359.c b/drivers/net/tokenring/3c359.c index 8a2e3c21a703..943850c411e9 100644 --- a/drivers/net/tokenring/3c359.c +++ b/drivers/net/tokenring/3c359.c @@ -314,7 +314,6 @@ int __devinit xl_probe(struct pci_dev *pdev, const struct pci_device_id *ent) 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 ; diff --git a/drivers/net/tokenring/ibmtr.c b/drivers/net/tokenring/ibmtr.c index 832c82ff339a..83b03d31fd62 100644 --- a/drivers/net/tokenring/ibmtr.c +++ b/drivers/net/tokenring/ibmtr.c @@ -187,7 +187,7 @@ char __devinit *adapter_def(char type) #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 __devinit find_turbo_adapters(int *iolist) { } } +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 @@ static void __devinit find_turbo_adapters(int *iolist) { * 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 @@ static int __init ibmtr_init(void) 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 @@ static void __exit ibmtr_cleanup(void) 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 --git a/drivers/net/tokenring/olympic.c b/drivers/net/tokenring/olympic.c index e419eef0f9be..3b15c2197888 100644 --- a/drivers/net/tokenring/olympic.c +++ b/drivers/net/tokenring/olympic.c @@ -228,7 +228,6 @@ static int __devinit olympic_probe(struct pci_dev *pdev, const struct pci_device #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 --git a/drivers/net/tokenring/tms380tr.c b/drivers/net/tokenring/tms380tr.c index 1931a5b05b3f..e781c816a344 100644 --- a/drivers/net/tokenring/tms380tr.c +++ b/drivers/net/tokenring/tms380tr.c @@ -147,7 +147,6 @@ static void tms380tr_hardware_send_packet(struct net_device *dev, 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 @@ static int madgemc_sifprobe(struct net_device *dev) } #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 @@ int tmsdev_init(struct net_device *dev, unsigned long dmalimit, } /* 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 --git a/drivers/net/wan/cosa.c b/drivers/net/wan/cosa.c index 43f4a3146907..6be377e64a08 100644 --- a/drivers/net/wan/cosa.c +++ b/drivers/net/wan/cosa.c @@ -594,40 +594,47 @@ err_out: /*---------- 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 --git a/drivers/net/wd.c b/drivers/net/wd.c index 179e0ec78266..cdd1eaeecdf1 100644 --- a/drivers/net/wd.c +++ b/drivers/net/wd.c @@ -129,12 +129,11 @@ static void cleanup_card(struct net_device *dev) { free_irq(dev->irq, dev); release_region(dev->base_addr - WD_NIC_OFFSET, WD_IO_EXTENT); - kfree(dev->priv); } struct net_device * __init wd_probe(int unit) { - struct net_device *dev = alloc_etherdev(0); + struct net_device *dev = alloc_ei_netdev(); int err; if (!dev) @@ -143,8 +142,6 @@ struct net_device * __init wd_probe(int unit) sprintf(dev->name, "eth%d", unit); netdev_boot_setup_check(dev); - dev->priv = NULL; /* until all 8390-based use alloc_etherdev() */ - err = do_wd_probe(dev); if (err) goto out; @@ -301,19 +298,11 @@ static int __init wd_probe1(struct net_device *dev, int ioaddr) } 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; } @@ -515,10 +504,9 @@ init_module(void) if (this_dev != 0) break; /* only autoprobe 1st one */ printk(KERN_NOTICE "wd.c: Presently autoprobing (not recommended) for a single card.\n"); } - dev = alloc_etherdev(0); + dev = alloc_ei_netdev(); if (!dev) break; - dev->priv = NULL; dev->irq = irq[this_dev]; dev->base_addr = io[this_dev]; dev->mem_start = mem[this_dev]; diff --git a/drivers/net/wireless/airport.c b/drivers/net/wireless/airport.c index 5a8ffb53c24d..5d80f9f2ba86 100644 --- a/drivers/net/wireless/airport.c +++ b/drivers/net/wireless/airport.c @@ -216,7 +216,7 @@ airport_attach(struct macio_dev *mdev, const struct of_match *match) 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 --git a/drivers/net/wireless/orinoco_pci.c b/drivers/net/wireless/orinoco_pci.c index 85f642b39e0e..625c15c10a17 100644 --- a/drivers/net/wireless/orinoco_pci.c +++ b/drivers/net/wireless/orinoco_pci.c @@ -261,7 +261,7 @@ static int orinoco_pci_init_one(struct pci_dev *pdev, if (dev->irq) free_irq(dev->irq, dev); - kfree(dev); + free_netdev(dev); } if (pci_ioaddr) diff --git a/drivers/net/wireless/orinoco_plx.c b/drivers/net/wireless/orinoco_plx.c index bc3b5d63f7d4..6a42fa18ff45 100644 --- a/drivers/net/wireless/orinoco_plx.c +++ b/drivers/net/wireless/orinoco_plx.c @@ -263,7 +263,7 @@ static int orinoco_plx_init_one(struct pci_dev *pdev, if (dev->irq) free_irq(dev->irq, dev); - kfree(dev); + free_netdev(dev); } if (pccard_ioaddr) diff --git a/drivers/net/wireless/orinoco_tmd.c b/drivers/net/wireless/orinoco_tmd.c index 7b551fbf3150..725e4b564e7a 100644 --- a/drivers/net/wireless/orinoco_tmd.c +++ b/drivers/net/wireless/orinoco_tmd.c @@ -157,7 +157,7 @@ static int orinoco_tmd_init_one(struct pci_dev *pdev, if (dev->irq) free_irq(dev->irq, dev); - kfree(dev); + free_netdev(dev); } if (pccard_ioaddr) diff --git a/drivers/net/wireless/ray_cs.c b/drivers/net/wireless/ray_cs.c index aaf15d355bad..82b049d22c71 100644 --- a/drivers/net/wireless/ray_cs.c +++ b/drivers/net/wireless/ray_cs.c @@ -344,19 +344,14 @@ static dev_link_t *ray_attach(void) 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 @@ static dev_link_t *ray_attach(void) 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 @@ static dev_link_t *ray_attach(void) 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 @@ static dev_link_t *ray_attach(void) 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 @@ static void ray_detach(dev_link_t *link) 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 --git a/drivers/net/wireless/wl3501_cs.c b/drivers/net/wireless/wl3501_cs.c index f5db2ef7860b..079ffd870369 100644 --- a/drivers/net/wireless/wl3501_cs.c +++ b/drivers/net/wireless/wl3501_cs.c @@ -1449,18 +1449,6 @@ fail: 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; @@ -2056,7 +2044,6 @@ static dev_link_t *wl3501_attach(void) 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 --git a/drivers/net/zorro8390.c b/drivers/net/zorro8390.c index a7cf490943c6..c3272c259185 100644 --- a/drivers/net/zorro8390.c +++ b/drivers/net/zorro8390.c @@ -103,10 +103,9 @@ static int __init zorro8390_probe(void) continue; board = z->resource.start; ioaddr = board+cards[i].offset; - dev = alloc_etherdev(0); + dev = alloc_ei_netdev(); if (!dev) return -ENOMEM; - dev->priv = NULL; SET_MODULE_OWNER(dev); if (!request_mem_region(ioaddr, NE_IO_EXTENT*2, dev->name)) { free_netdev(dev); @@ -197,13 +196,6 @@ static int __init zorro8390_init(struct net_device *dev, unsigned long board, 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"); - free_irq(IRQ_AMIGA_PORTS, dev); - return -ENOMEM; - } - for(i = 0; i < ETHER_ADDR_LEN; i++) { #ifdef DEBUG printk(" %2.2x", SA_prom[i]); @@ -236,10 +228,8 @@ static int __init zorro8390_init(struct net_device *dev, unsigned long board, #endif NS8390_init(dev, 0); err = register_netdev(dev); - if (err) { - kfree(dev->priv); + if (err) free_irq(IRQ_AMIGA_PORTS, dev); - } return err; } @@ -421,7 +411,6 @@ static void __exit zorro8390_cleanup(void) unregister_netdev(dev); free_irq(IRQ_AMIGA_PORTS, dev); release_mem_region(ZTWO_PADDR(dev->base_addr), NE_IO_EXTENT*2); - kfree(dev->priv); free_netdev(dev); root_zorro8390_dev = next; } diff --git a/drivers/s390/net/qeth.c b/drivers/s390/net/qeth.c index a01fb0c89c18..8f660aa7ea2f 100644 --- a/drivers/s390/net/qeth.c +++ b/drivers/s390/net/qeth.c @@ -9802,28 +9802,28 @@ static int 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 --git a/include/linux/arcdevice.h b/include/linux/arcdevice.h index 66c7495e1834..3a3759fcebdb 100644 --- a/include/linux/arcdevice.h +++ b/include/linux/arcdevice.h @@ -331,6 +331,7 @@ void arcnet_dump_packet(struct net_device *dev, int bufnum, char *desc); 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 --git a/include/linux/com20020.h b/include/linux/com20020.h index 2c5fc4294a06..c88d530bf637 100644 --- a/include/linux/com20020.h +++ b/include/linux/com20020.h @@ -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 --git a/include/linux/if_bonding.h b/include/linux/if_bonding.h index 4419670188d2..0f2382b5c755 100644 --- a/include/linux/if_bonding.h +++ b/include/linux/if_bonding.h @@ -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 <amir.noam at intel dot com> * - Added support for getting slave's speed and duplex via ethtool. * Needed for 802.3ad and other future modes. - * + * * 2003/03/18 - Tsippy Mendelson <tsippy.mendelson at intel dot com> and * Shmulik Hen <shmulik.hen at intel dot com> * - Enable support of modes that need to use the unique mac address of @@ -42,7 +42,7 @@ #include <linux/if_ether.h> /* 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 +77,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; @@ -90,9 +86,9 @@ typedef struct ifbond { typedef struct ifslave { __s32 slave_id; /* Used as an IN param to the BOND_SLAVE_INFO_QUERY ioctl */ - char slave_name[IFNAMSIZ]; - char link; - char state; + __s8 slave_name[IFNAMSIZ]; + __s8 link; + __s8 state; __u32 link_failure_count; } ifslave; @@ -115,3 +111,4 @@ struct ad_info { * tab-width: 8 * End: */ + diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 1a77c3caf115..ebc9426684ba 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -474,8 +474,15 @@ struct net_device /* 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. diff --git a/include/net/atmclip.h b/include/net/atmclip.h index 394eb72b5234..47048b1d179a 100644 --- a/include/net/atmclip.h +++ b/include/net/atmclip.h @@ -44,7 +44,7 @@ struct atmarp_entry { }; -#define PRIV(dev) ((struct clip_priv *) ((struct net_device *) (dev)+1)) +#define PRIV(dev) ((struct clip_priv *) netdev_priv(dev)) struct clip_priv { diff --git a/net/atm/clip.c b/net/atm/clip.c index 811e2f2bc444..e6971cd6213a 100644 --- a/net/atm/clip.c +++ b/net/atm/clip.c @@ -563,32 +563,20 @@ static int clip_setentry(struct atm_vcc *vcc,u32 ip) } -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 @@ static int clip_create(int number) 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 @@ static int clip_device_event(struct notifier_block *this,unsigned long event, { /* 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 --git a/net/bridge/br_if.c b/net/bridge/br_if.c index 9450f1d7a711..47f61382916a 100644 --- a/net/bridge/br_if.c +++ b/net/bridge/br_if.c @@ -172,7 +172,7 @@ int br_add_bridge(const char *name) ret = register_netdev(br->dev); if (ret) - kfree(br->dev); + free_netdev(br->dev); return ret; } diff --git a/net/core/dev.c b/net/core/dev.c index d1dfcef63c5a..c10acfc613e7 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -3043,7 +3043,7 @@ void free_netdev(struct net_device *dev) { /* Compatiablity with error handling in drivers */ if (dev->reg_state == NETREG_UNINITIALIZED) { - kfree(dev); + kfree((char *)dev - dev->padded); return; } diff --git a/net/core/net-sysfs.c b/net/core/net-sysfs.c index 5281a1eb6c0b..5720ca0d621a 100644 --- a/net/core/net-sysfs.c +++ b/net/core/net-sysfs.c @@ -372,7 +372,7 @@ static void netdev_release(struct class_device *cd) BUG_ON(dev->reg_state != NETREG_RELEASED); - kfree(dev); + kfree((char *)dev - dev->padded); } static struct class net_class = { |
