Commit 5db5272c authored by Linus Torvalds's avatar Linus Torvalds

v2.4.14 -> v2.4.14.1

  - me: fix page flags race condition Andrea found
  - David Miller: sparc and network updates
  - various: fix loop driver that thought it was part of the VM system
  - me: teach DRM about VM_RESERVED
  - Alan Cox: more merging
parent aad40ef3
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -971,7 +971,7 @@ Your cooperation is appreciated.
0 = /dev/rd/c0d0 First disk, whole disk
8 = /dev/rd/c0d1 Second disk, whole disk
...
248 = /dev/rd/c0d15 32nd disk, whole disk
248 = /dev/rd/c0d31 32nd disk, whole disk
For partitions add:
0 = /dev/rd/c?d? Whole disk
......
......@@ -471,6 +471,11 @@ your system and how much traffic was routed over those devices:
...] 1375103 17405 0 0 0 0 0 0
...] 1703981 5535 0 0 0 3 0 0
In addition, each Channel Bond interface has it's own directory. For
example, the bond0 device will have a directory called /proc/net/bond0/.
It will contain information that is specific to that bond, such as the
current slaves of the bond, the link status of the slaves, and how
many times the slaves link has failed.
1.5 SCSI info
-------------
......
......@@ -2,7 +2,7 @@
----------------------------
H. Peter Anvin <hpa@zytor.com>
Last update 2000-07-27
Last update 2000-10-29
On the i386 platform, the Linux kernel uses a rather complicated boot
convention. This has evolved partially due to historical aspects, as
......@@ -145,6 +145,9 @@ directly. Such boot loaders do not need to worry about filling in
most of the fields in the header. The following fields should be
filled out, however:
vid_mode:
Please see the section on SPECIAL COMMAND LINE OPTIONS.
type_of_loader:
If your boot loader has an assigned id (see table below), enter
0xTV here, where T is an identifier for the boot loader and V is
......@@ -319,8 +322,8 @@ conflict with actual kernel options now or in the future.
mem=<size>
<size> is an integer in C notation optionally followed by K, M
or G (meaning << 10, << 20 or << 30). This specifies to the
kernel the memory size. This affects the possible placement
or G (meaning << 10, << 20 or << 30). This specifies the end
of memory to the kernel. This affects the possible placement
of an initrd, since an initrd should be placed near end of
memory. Note that this is an option to *both* the kernel and
the bootloader!
......@@ -392,8 +395,8 @@ following hooks that, if set, are invoked by the kernel at the
appropriate time. The use of these hooks should probably be
considered an absolutely last resort!
IMPORTANT: All the hooks are required to preserve %ebp, %esi and %edi
across invocation.
IMPORTANT: All the hooks are required to preserve %esp, %ebp, %esi and
%edi across invocation.
realmode_swtch:
A 16-bit real mode far subroutine invoked immediately before
......
Linux Ethernet Bonding Driver mini-howto
Initial release : Thomas Davis <tadavis at lbl.gov>
Corrections, HA extensions : 2000/10/03-15 :
- Willy Tarreau <willy at meta-x.org>
- Constantine Gavrilov <const-g at xpert.com>
- Chad N. Tindel <ctindel at ieee dot org>
- Janice Girouard <girouard at us dot ibm dot com>
Note :
------
The bonding driver originally came from Donald Becker's beowulf patches for
kernel 2.0. It has changed quite a bit since, and the original tools from
extreme-linux and beowulf sites will not work with this version of the driver.
For new versions of the driver, patches for older kernels and the updated
userspace tools, please follow the links at the end of this file.
Installation
============
1) Build kernel with the bonding driver
---------------------------------------
For the latest version of the bonding driver, use kernel 2.4.12 or above
(otherwise you will need to apply a patch).
Configure kernel with `make menuconfig/xconfig/config', and select
"Bonding driver support" in the "Network device support" section. It is
recommended to configure the driver as module since it is currently the only way
to pass parameters to the driver and configure more than one bonding device.
Build and install the new kernel and modules.
2) Get and install the userspace tools
--------------------------------------
This version of the bonding driver requires updated ifenslave program. The
original one from extreme-linux and beowulf will not work. Kernels 2.4.12
and above include the updated version of ifenslave.c in Documentation/network
directory. For older kernels, please follow the links at the end of this file.
IMPORTANT!!! If you are running on Redhat 7.1 or greater, you need
to be careful because /usr/include/linux is no longer a symbolic link
to /usr/src/linux/include/linux. If you build ifenslave while this is
true, ifenslave will appear to succeed but your bond won't work. The purpose
of the -I option on the ifenslave compile line is to make sure it uses
/usr/src/linux/include/linux/if_bonding.h instead of the version from
/usr/include/linux.
To install ifenslave.c, do:
# gcc -Wall -Wstrict-prototypes -O -I/usr/src/linux/include ifenslave.c -o ifenslave
# cp ifenslave /sbin/ifenslave
3) Configure your system
------------------------
Also see the following section on the module parameters. You will need to add
at least the following line to /etc/conf.modules (or /etc/modules.conf):
alias bond0 bonding
Use standard distribution techniques to define bond0 network interface. For
example, on modern RedHat distributions, create ifcfg-bond0 file in
/etc/sysconfig/network-scripts directory that looks like this:
DEVICE=bond0
IPADDR=192.168.1.1
NETMASK=255.255.255.0
NETWORK=192.168.1.0
BROADCAST=192.168.1.255
ONBOOT=yes
BOOTPROTO=none
USERCTL=no
(put the appropriate values for you network instead of 192.168.1).
All interfaces that are part of the trunk, should have SLAVE and MASTER
definitions. For example, in the case of RedHat, if you wish to make eth0 and
eth1 (or other interfaces) a part of the bonding interface bond0, their config
files (ifcfg-eth0, ifcfg-eth1, etc.) should look like this:
DEVICE=eth0
USERCTL=no
ONBOOT=yes
MASTER=bond0
SLAVE=yes
BOOTPROTO=none
(use DEVICE=eth1 for eth1 and MASTER=bond1 for bond1 if you have configured
second bonding interface).
Restart the networking subsystem or just bring up the bonding device if your
administration tools allow it. Otherwise, reboot. (For the case of RedHat
distros, you can do `ifup bond0' or `/etc/rc.d/init.d/network restart'.)
If the administration tools of your distribution do not support master/slave
notation in configuration of network interfaces, you will need to configure
the bonding device with the following commands manually:
# /sbin/ifconfig bond0 192.168.1.1 up
# /sbin/ifenslave bond0 eth0
# /sbin/ifenslave bond0 eth1
(substitute 192.168.1.1 with your IP address and add custom network and custom
netmask to the arguments of ifconfig if required).
You can then create a script with these commands and put it into the appropriate
rc directory.
If you specifically need that all your network drivers are loaded before the
bonding driver, use one of modutils' powerful features : in your modules.conf,
tell that when asked for bond0, modprobe should first load all your interfaces :
probeall bond0 eth0 eth1 bonding
Be careful not to reference bond0 itself at the end of the line, or modprobe will
die in an endless recursive loop.
4) Module parameters.
---------------------
The following module parameters can be passed:
mode=
Possible values are 0 (round robin policy, default) and 1 (active backup
policy), and 2 (XOR). See question 9 and the HA section for additional info.
miimon=
Use integer value for the frequency (in ms) of MII link monitoring. Zero value
is default and means the link monitoring will be disabled. A good value is 100
if you wish to use link monitoring. See HA section for additional info.
downdelay=
Use integer value for delaying disabling a link by this number (in ms) after
the link failure has been detected. Must be a multiple of miimon. Default
value is zero. See HA section for additional info.
updelay=
Use integer value for delaying enabling a link by this number (in ms) after
the "link up" status has been detected. Must be a multiple of miimon. Default
value is zero. See HA section for additional info.
arp_interval=
Use integer value for the frequency (in ms) of arp monitoring. Zero value
is default and means the arp monitoring will be disabled. See HA section
for additional info. This field is value in active_backup mode only.
arp_ip_target=
An ip address to use when arp_interval is > 0. This is the target of the
arp request sent to determine the health of the link to the target.
Specify this value in ddd.ddd.ddd.ddd format.
If you need to configure several bonding devices, the driver must be loaded
several times. I.e. for two bonding devices, your /etc/conf.modules must look
like this:
alias bond0 bonding
alias bond1 bonding
options bond0 miimon=100
options bond1 -o bonding1 miimon=100
5) Testing configuration
------------------------
You can test the configuration and transmit policy with ifconfig. For example,
for round robin policy, you should get something like this:
[root]# /sbin/ifconfig
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
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
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
Questions :
===========
1. Is it SMP safe?
Yes. The old 2.0.xx channel bonding patch was not SMP safe.
The new driver was designed to be SMP safe from the start.
2. What type of cards will work with it?
Any Ethernet type cards (you can even mix cards - a Intel
EtherExpress PRO/100 and a 3com 3c905b, for example).
You can even bond together Gigabit Ethernet cards!
3. How many bonding devices can I have?
One for each module you load. See section on module parameters for how
to accomplish this.
4. How many slaves can a bonding device have?
Limited by the number of network interfaces Linux supports and the
number of cards you can place in your system.
5. What happens when a slave link dies?
If your ethernet cards support MII 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 HA for additional information.
For ethernet cards not supporting MII status, or if you wish to
verify that packets have been both send and received, you may
configure the arp_interval and arp_ip_target. If packets have
not been sent or received during this interval, an arp request
is sent to the target to generate send and receive traffic.
If after this interval, either the successful send and/or
receive count has not incremented, the next slave in the sequence
will become the active 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
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).
6. Can bonding be used for High Availability?
Yes, if you use MII monitoring and ALL your cards support MII link
status reporting. See section on HA for more information.
7. Which switches/systems does it work with?
In round-robin mode, it works with systems that support trunking:
* Cisco 5500 series (look for EtherChannel support).
* SunTrunking software.
* Alteon AceDirector switches / WebOS (use Trunks).
* BayStack Switches (trunks must be explicitly configured). Stackable
models (450) can define trunks between ports on different physical
units.
* Linux bonding, of course !
In Active-backup mode, it should work with any Layer-II switches.
8. Where does a bonding device get its MAC address from?
If not explicitly configured with ifconfig, the MAC address of the
bonding device is taken from its first slave device. This MAC address
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 ha 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
example) and reload them to get the MAC addresses from their
eeproms. If the driver is shared by several devices, you need
to turn them all down. Another solution is to look for the MAC
address at boot time (dmesg or tail /var/log/messages) and to
reset it by hand with ifconfig :
# ifconfig eth0 down
# ifconfig eth0 hw ether 00:20:40:60:80:A0
9. Which transmit polices can be used?
Round robin, based on the order of enslaving, the output device
is selected base on the next available slave. Regardless of
the source and/or destination of the packet.
XOR, based on (src hw addr XOR dst hw addr) % slave cnt. This
selects the same slave for each destination hw address.
Active-backup policy that ensures that one and only one device will
transmit at any given moment. Active-backup policy is useful for
implementing high availability solutions using two hubs (see
section on HA).
High availability
=================
To implement high availability using the bonding driver, you need to
compile the driver as 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 status reporting. You need to
verify that all your interfaces support MII link status reporting. On Linux
kernel 2.2.17, all the 100 Mbps capable drivers and yellowfin gigabit driver
support it. If your system has an interface that does not support MII status
reporting, a failure of its link will not be detected!
The bonding driver can regularly check all its slaves links 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 ms on i386) because it may then reduce the system interactivity. 100 ms
seems to be a good value. It means that a dead link will be detected at most
100 ms after it goes down.
Example:
# modprobe bonding miimon=100
Or, put in your /etc/modules.conf :
alias bond0 bonding
options bond0 miimon=100
There are currently two policies for high availability, depending on whether
a) hosts are connected to a single host or switch that support trunking
b) hosts are connected to several different switches or a single switch that
does not support trunking.
1) HA on a single switch or host - load balancing
-------------------------------------------------
It is the easiest to set up and to understand. Simply configure the
remote equipment (host or switch) to aggregate traffic over several
ports (Trunk, EtherChannel, etc.) and configure the bonding interfaces.
If the module has been loaded with the proper MII option, it will work
automatically. You can then try to remove and restore different links
and see in your logs what the driver detects. When testing, you may
encounter problems on some buggy switches that disable the trunk for a
long time if all ports in a trunk go down. This is not Linux, but really
the switch (reboot it to ensure).
Example 1 : host to host at double speed
+----------+ +----------+
| |eth0 eth0| |
| Host A +--------------------------+ Host B |
| +--------------------------+ |
| |eth1 eth1| |
+----------+ +----------+
On each host :
# modprobe bonding miimon=100
# ifconfig bond0 addr
# ifenslave bond0 eth0 eth1
Example 2 : host to switch at double speed
+----------+ +----------+
| |eth0 port1| |
| Host A +--------------------------+ switch |
| +--------------------------+ |
| |eth1 port2| |
+----------+ +----------+
On host A : On the switch :
# modprobe bonding miimon=100 # set up a trunk on port1
# ifconfig bond0 addr and port2
# ifenslave bond0 eth0 eth1
2) HA 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
are multiple ports and the host's MAC address should be visible on one
port only to avoid confusing the switches.
If you need to know which interface is the active one, and which ones are
backup, use ifconfig. All backup interfaces have the NOARP flag set.
To use this mode, pass "mode=1" to the module at load time :
# modprobe bonding miimon=100 mode=1
Or, put in your /etc/modules.conf :
alias bond0 bonding
options bond0 miimon=100 mode=1
Example 1: Using multiple host and multiple switches to build a "no single
point of failure" solution.
| |
|port3 port3|
+-----+----+ +-----+----+
| |port7 ISL port7| |
| switch A +--------------------------+ switch B |
| +--------------------------+ |
| |port8 port8| |
+----++----+ +-----++---+
port2||port1 port1||port2
|| +-------+ ||
|+-------------+ host1 +---------------+|
| eth0 +-------+ eth1 |
| |
| +-------+ |
+--------------+ host2 +----------------+
eth0 +-------+ eth1
In this configuration, there are an ISL - Inter Switch Link (could be a trunk),
several servers (host1, host2 ...) attached to both switches each, and one or
more ports to the outside world (port3...). One an only one slave on each host
is active at a time, while all links are still monitored (the system can
detect a failure of active and backup links).
Each time a host changes its active interface, it sticks to the new one until
it goes down. In this example, the hosts are not too much affected by the
expiration time of the switches' forwarding tables.
If host1 and host2 have the same functionality and are used in load balancing
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.
Example 2: Using multiple ethernet cards connected to a switch to configure
NIC failover (switch is not required to support trunking).
+----------+ +----------+
| |eth0 port1| |
| Host A +--------------------------+ switch |
| +--------------------------+ |
| |eth1 port2| |
+----------+ +----------+
On host A : On the switch :
# modprobe bonding miimon=100 mode=1 # (optional) minimize the time
# ifconfig bond0 addr # for table expiration
# ifenslave bond0 eth0 eth1
Each time the host changes its active interface, it sticks to the new one until
it goes down. In this example, the host is strongly affected by the expiration
time of the switch forwarding table.
3) Adapting to your switches' timing
------------------------------------
If your switches take a long time to go into backup mode, it may be
desirable not to activate a backup interface immediately after a link goes
down. It is possible to delay the moment at which a link will be
completely disabled by passing the module parameter "downdelay" (in
milliseconds, must be a multiple of miimon).
When a switch reboots, it is possible that its ports report "link up" status
before they become usable. This could fool a bond device by causing it to
use some ports that are not ready yet. It is possible to delay the moment at
which an active link will be reused by passing the module parameter "updelay"
(in milliseconds, must be a multiple of miimon).
A similar situation can occur when a host re-negotiates a lost link with the
switch (a case of cable replacement).
A special case is when a bonding interface has lost all slave links. Then the
driver will immediately reuse the first link that goes up, even if updelay
parameter was specified. (If there are slave interfaces in the "updelay" state,
the interface that first went into that state will be immediately reused.) This
allows to reduce down-time if the value of updelay has been overestimated.
Examples :
# modprobe bonding miimon=100 mode=1 downdelay=2000 updelay=5000
# modprobe bonding miimon=100 mode=0 downdelay=0 updelay=5000
4) Limitations
--------------
The main limitations are :
- only the link status is monitored. If the switch on the other side is
partially down (e.g. doesn't forward anymore, but the link is OK), the link
won't be disabled. Another way to check for a dead link could be to count
incoming frames on a heavily loaded host. This is not applicable to small
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.
Resources and links
===================
Current developement on this driver is posted to:
- http://www.sourceforge.net/projects/bonding/
Donald Becker's Ethernet Drivers and diag programs may be found at :
- http://www.scyld.com/network/
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 :
- http://wtarreau.free.fr/pub/bonding/
- http://www-miaif.lip6.fr/willy/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/
-- END --
/* Mode: C;
* ifenslave.c: Configure network interfaces for parallel routing.
*
* 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
*
* This program is free software; you can redistribute it
* and/or modify it under the terms of the GNU General Public
* License as published by the Free Software Foundation.
*
* The author may be reached as becker@CESDIS.gsfc.nasa.gov, or C/O
* Center of Excellence in Space Data and Information Sciences
* Code 930.5, Goddard Space Flight Center, Greenbelt MD 20771
*
* Changes :
* - 2000/10/02 Willy Tarreau <willy at meta-x.org> :
* - few fixes. Master's MAC address is now correctly taken from
* the first device when not previously set ;
* - detach support : call BOND_RELEASE to detach an enslaved interface.
* - give a mini-howto from command-line help : # ifenslave -h
*
* - 2001/02/16 Chad N. Tindel <ctindel at ieee dot org> :
* - Master is now brought down before setting the MAC address. In
* the 2.4 kernel you can't change the MAC address while the device is
* up because you get EBUSY.
*
* - 2001/09/13 Takao Indoh <indou dot takao at jp dot fujitsu dot com>
* - Added the ability to change the active interface on a mode 1 bond
* at runtime.
*
* - 2001/10/23 Chad N. Tindel <ctindel at ieee dot org> :
* - No longer set the MAC address of the master. The bond device will
* take care of this itself
* - Try the SIOC*** versions of the bonding ioctls before using the
* old versions
*/
static char *version =
"ifenslave.c:v0.07 9/9/97 Donald 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";
static const char *usage_msg =
"Usage: ifenslave [-adfrvVh] <master-interface> < <slave-if> [metric <N>] > ...\n"
" ifenslave -c master-interface slave-if\n";
static const char *howto_msg =
"Usage: ifenslave [-adfrvVh] <master-interface> < <slave-if> [metric <N>] > ...\n"
" ifenslave -c master-interface slave-if\n"
"\n"
" To create a bond device, simply follow these three steps :\n"
" - ensure that the required drivers are properly loaded :\n"
" # modprobe bonding ; modprobe <3c59x|eepro100|pcnet32|tulip|...>\n"
" - 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"
" 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"
"\n"
" To set the bond device down and automatically release all the slaves :\n"
" # ifconfig bond0 down\n"
"\n"
" To change active slave :\n"
" # ifenslave -c bond0 eth0\n"
"\n";
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <getopt.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <linux/if.h>
#include <linux/if_arp.h>
#include <linux/if_ether.h>
#include <linux/if_bonding.h>
#include <linux/sockios.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 }
};
/* 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. */
static void if_print(char *ifname);
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 goterr = 0;
int c, errflag = 0;
sa_family_t master_family;
char **spp, *master_ifname, *slave_ifname;
int hwaddr_notset;
while ((c = getopt_long(argc, argv, "acdfrvV?h", 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 ) {
fprintf(stderr, usage_msg);
return 2;
}
if (errflag) {
fprintf(stderr, usage_msg);
return 2;
}
if (opt_howto) {
fprintf(stderr, howto_msg);
return 0;
}
if (verbose || opt_version) {
printf(version);
if (opt_version)
exit(0);
}
/* Open a basic socket. */
if ((skfd = socket(AF_INET, SOCK_DGRAM,0)) < 0) {
perror("socket");
exit(-1);
}
if (verbose)
fprintf(stderr, "DEBUG: argc=%d, optind=%d and argv[optind] is %s.\n",
argc, optind, argv[optind]);
/* No remaining args means show all interfaces. */
if (optind == argc) {
if_print((char *)NULL);
(void) close(skfd);
exit(0);
}
/* 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);
return 2;
}
}
/* A single args means show the configuration for this interface. */
if (slave_ifname == NULL) {
if_print(master_ifname);
(void) close(skfd);
exit(0);
}
/* 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));
}
}
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;
}
/* 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);
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]);
}
}
/* 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 { /* 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 { /* attach a slave interface to the master */
/* two possibilities :
- if hwaddr_notset, do nothing. The bond will assign the
hwaddr from it's first slave.
- if !hwaddr_notset, assign the master's hwaddr to each slave
*/
if (hwaddr_notset) { /* we do nothing */
}
else { /* we'll assign master's hwaddr to this slave */
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));
return 1;
}
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]);
}
}
}
if (*spp && !strcmp(*spp, "metric")) {
if (*++spp == NULL) {
fprintf(stderr, usage_msg);
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++;
}
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]);
}
}
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);
}
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]);
}
}
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 (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]);
}
}
ifr2.ifr_flags |= IFF_UP; /* the interface will need to be up to be bonded */
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);
}
/* Do the real thing */
if ( ! opt_r) {
strncpy(if_flags.ifr_name, master_ifname, IFNAMSIZ);
strncpy(if_flags.ifr_slave, slave_ifname, IFNAMSIZ);
if (!opt_c) {
if ((ioctl(skfd, SIOCBONDENSLAVE, &if_flags) < 0) &&
(ioctl(skfd, BOND_ENSLAVE_OLD, &if_flags) < 0)) {
fprintf(stderr, "SIOCBONDENSLAVE: %s.\n", strerror(errno));
}
}
else {
if ((ioctl(skfd, SIOCBONDCHANGEACTIVE, &if_flags) < 0) &&
(ioctl(skfd, BOND_CHANGE_ACTIVE_OLD, &if_flags) < 0)) {
fprintf(stderr, "SIOCBONDCHANGEACTIVE: %s.\n", strerror(errno));
}
}
}
}
} while ( (slave_ifname = *spp++) != NULL);
/* Close the socket. */
(void) close(skfd);
return(goterr);
}
static short mif_flags;
/* Get the inteface configuration from the kernel. */
static int if_getconfig(char *ifname)
{
struct ifreq ifr;
int metric, mtu; /* Parameters of the master interface. */
struct sockaddr dstaddr, broadaddr, netmask;
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);
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]);
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]);
}
strcpy(ifr.ifr_name, ifname);
if (ioctl(skfd, SIOCGIFMETRIC, &ifr) < 0) {
metric = 0;
} else
metric = ifr.ifr_metric;
strcpy(ifr.ifr_name, ifname);
if (ioctl(skfd, SIOCGIFMTU, &ifr) < 0)
mtu = 0;
else
mtu = ifr.ifr_mtu;
strcpy(ifr.ifr_name, ifname);
if (ioctl(skfd, SIOCGIFDSTADDR, &ifr) < 0) {
memset(&dstaddr, 0, sizeof(struct sockaddr));
} else
dstaddr = ifr.ifr_dstaddr;
strcpy(ifr.ifr_name, ifname);
if (ioctl(skfd, SIOCGIFBRDADDR, &ifr) < 0) {
memset(&broadaddr, 0, sizeof(struct sockaddr));
} else
broadaddr = ifr.ifr_broadaddr;
strcpy(ifr.ifr_name, ifname);
if (ioctl(skfd, SIOCGIFNETMASK, &ifr) < 0) {
memset(&netmask, 0, sizeof(struct sockaddr));
} else
netmask = ifr.ifr_netmask;
return(0);
}
static void if_print(char *ifname)
{
char buff[1024];
struct ifconf ifc;
struct ifreq *ifr;
int i;
if (ifname == (char *)NULL) {
ifc.ifc_len = sizeof(buff);
ifc.ifc_buf = buff;
if (ioctl(skfd, SIOCGIFCONF, &ifc) < 0) {
fprintf(stderr, "SIOCGIFCONF: %s\n", strerror(errno));
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);
continue;
}
if (((mif_flags & IFF_UP) == 0) && !opt_a) continue;
/*ife_print(&ife);*/
}
} else {
if (if_getconfig(ifname) < 0)
fprintf(stderr, "%s: unknown interface.\n", ifname);
}
}
/*
* Local variables:
* version-control: t
* kept-new-versions: 5
* c-indent-level: 4
* c-basic-offset: 4
* tab-width: 4
* compile-command: "gcc -Wall -Wstrict-prototypes -O -I/usr/src/linux/include ifenslave.c -o ifenslave"
* End:
*/
......@@ -31,6 +31,7 @@ de4x5 YES YES YES Hardware
de600 NO NO NO N/A
de620 PROMISC PROMISC YES Software
depca YES PROMISC YES Hardware
dmfe YES YES YES Software(*)
e2100 YES YES YES Hardware
eepro YES PROMISC YES Hardware
eexpress NO NO NO N/A
......@@ -52,9 +53,12 @@ sunlance YES YES YES Hardware
tulip YES YES YES Hardware
wavelan YES PROMISC YES Hardware
wd YES YES YES Hardware
xirc2ps_cs YES YES YES Hardware
znet YES YES YES Software
PROMISC = This multicast mode is in fact promiscuous mode. Avoid using
cards who go PROMISC on any multicast in a multicast kernel.
(#) = Hardware multicast support is not used yet.
(*) = Hardware support for Davicom 9132 chipset only.
......@@ -1287,10 +1287,14 @@ this can make debugging a particular process under VM painful under normal
circumstances as the process may change when doing a
TR I R <address range>.
Thankfully after reading VM's online help I figured out how to debug
I particular process.
particular processes in 31 bit mode, however, according to the current
VM online help documentation the method described below uses
TR STO or STD which don't currently work on z/Series while in
64-bit mode.
Your first problem is to find the STD ( segment table designation )
of the program you wish to debug.
There are several ways you can do this here are a few
1) objdump --syms <program to be debugged> | grep main
To get the address of main in the program.
......
......@@ -56,7 +56,7 @@ will allow only devno's 0x480e & 0x480f to be autodetected.
.El
.Bl -item
.It
Multiple options can be passed separated by semicolons but no spaces are allowed between parameters. To be consistent with other hotpluggable architectures the script pointed to /proc/sys/kernel/hotplug (normally /sbin/hotplug) will be called automatically on startup or a machine check of a device as follows.
Multiple options can be passed separated by semicolons, no spaces or newlines are allowed between parameters on the kernel parameter line as it complicates parsing, spaces are allowed in /proc/chandev & chandev.conf, newlines are allowed in chandev.conf only. To be consistent with other hotpluggable architectures the script pointed to /proc/sys/kernel/hotplug (normally /sbin/hotplug) will be called automatically on startup or a machine check of a device as follows.
/sbin/hotplug chandev <start starting_devnames> <machine_check (devname last/pre_recovery_status) (current/post_recovery_status)>.
The chandev layer doesn't open stdin stdout or stderr so it is advisable that you add the following lines to the start of your script, here is a sample script which starts devices as they become available.
.It
......@@ -132,7 +132,7 @@ e.g. ctc0,0x7c00,0x7c01
.It
Tells the channel layer to force ctc0 if detected to use cuu's 7c00 & 7c01 port,port_no is the relative adapter no on lcs, on ctc/escon this field is the ctc/escon protocol number ( default 0 ), don't do checksumming on received ip packets & as ctc doesn't have hardware stats so it ignores this parameter. This can be used for instance to force a device if it presents bad sense data to the IO layer & thus autodetection fails.
.It
lcs,0x7c00,0x7d00,-1,4096
lcs,0x7c00,0x7d00,4096,-1
All devices between 0x7c00 & 7d00 should be detected as lcs, let the driver use 4096k for each instance, don't care what port relative adapter number is chosen, don't checksum received ip packets & use hw stats .
.It
qeth1,0x7c00,0x7c01,0x7c02
......
......@@ -201,6 +201,12 @@ P: Dave Gilbert
M: linux@treblig.org
S: Maintained
ARM/SHARK MACHINE SUPPORT
P: Alexander Schulz
M: alex@shark-linux.de
W: http://www.shark-linux.de/shark.html
S: Maintained
ARM/STRONGARM110 PORT
P: Russell King
M: rmk@arm.linux.org.uk
......
VERSION = 2
PATCHLEVEL = 4
SUBLEVEL = 14
EXTRAVERSION =
SUBLEVEL = 15
EXTRAVERSION =-pre1
KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
......
......@@ -7,9 +7,10 @@
#include <linux/slab.h>
#include <asm/io.h>
#include <linux/pm.h>
#include <linux/keyboard.h>
#include <asm/keyboard.h>
#include <asm/system.h>
unsigned long dmi_broken;
int is_sony_vaio_laptop;
struct dmi_header
......@@ -87,7 +88,7 @@ static int __init dmi_table(u32 base, int len, int num, void (*decode)(struct dm
}
int __init dmi_iterate(void (*decode)(struct dmi_header *))
static int __init dmi_iterate(void (*decode)(struct dmi_header *))
{
unsigned char buf[20];
long fp=0xE0000L;
......@@ -98,7 +99,7 @@ int __init dmi_iterate(void (*decode)(struct dmi_header *))
* Skip on x86/64 with simnow. Will eventually go away
* If you see this ifdef in 2.6pre mail me !
*/
return;
return -1;
#endif
while( fp < 0xFFFFF)
......@@ -315,15 +316,14 @@ static __init int broken_apm_power(struct dmi_blacklist *d)
return 0;
}
#if defined(CONFIG_SONYPI) || defined(CONFIG_SONYPI_MODULE)
/*
* Check for a Sony Vaio system in order to enable the use of
* the sonypi driver (we don't want this driver to be used on
* other systems, even if they have the good PCI IDs).
* Check for a Sony Vaio system
*
* This one isn't a bug detect for those who asked, we simply want to
* activate Sony specific goodies like the camera and jogdial..
* On a Sony system we want to enable the use of the sonypi
* driver for Sony-specific goodies like the camera and jogdial.
* We also want to avoid using certain functions of the PnP BIOS.
*/
static __init int sony_vaio_laptop(struct dmi_blacklist *d)
{
if (is_sony_vaio_laptop == 0)
......@@ -333,7 +333,6 @@ static __init int sony_vaio_laptop(struct dmi_blacklist *d)
}
return 0;
}
#endif
/*
* This bios swaps the APM minute reporting bytes over (Many sony laptops
......@@ -359,11 +358,43 @@ static __init int broken_pirq(struct dmi_blacklist *d)
printk(KERN_INFO " *** Possibly defective BIOS detected (irqtable)\n");
printk(KERN_INFO " *** Many BIOSes matching this signature have incorrect IRQ routing tables.\n");
printk(KERN_INFO " *** If you see IRQ problems, in paticular SCSI resets and hangs at boot\n");
printk(KERN_INFO " *** contact your vendor and ask about updates.\n");
printk(KERN_INFO " *** contact your hardware vendor and ask about updates.\n");
printk(KERN_INFO " *** Building an SMP kernel may evade the bug some of the time.\n");
return 0;
}
/*
* ASUS K7V-RM has broken ACPI table defining sleep modes
*/
static __init int broken_acpi_Sx(struct dmi_blacklist *d)
{
printk(KERN_WARNING "Detected ASUS mainboard with broken ACPI sleep table\n");
dmi_broken |= BROKEN_ACPI_Sx;
return 0;
}
/*
* Toshiba keyboard likes to repeat keys when they are not repeated.
*/
static __init int broken_toshiba_keyboard(struct dmi_blacklist *d)
{
printk(KERN_WARNING "Toshiba with broken keyboard detected. If your keyboard sometimes generates 3 keypresses instead of one, contact pavel@ucw.cz\n");
return 0;
}
/*
* Toshiba fails to preserve interrupts over S1
*/
static __init int init_ints_after_s1(struct dmi_blacklist *d)
{
printk(KERN_WARNING "Toshiba with broken S1 detected.\n");
dmi_broken |= BROKEN_INIT_AFTER_S1;
return 0;
}
/*
* Some Bioses enable the PS/2 mouse (touchpad) at resume, even if it
* was disabled before the suspend. Linux gets terribly confused by that.
......@@ -380,11 +411,20 @@ static __init int broken_ps2_resume(struct dmi_blacklist *d)
pm_kbd_request_override = pckbd_pm_resume;
printk(KERN_INFO "%s machine detected. Mousepad Resume Bug workaround enabled.\n", d->ident);
}
#endif
#endif
return 0;
}
/*
* Simple "print if true" callback
*/
static __init int print_if_true(struct dmi_blacklist *d)
{
printk("%s\n", d->ident);
return 0;
}
/*
* Process the DMI blacklists
......@@ -428,10 +468,6 @@ static __initdata struct dmi_blacklist dmi_blacklist[]={
MATCH(DMI_PRODUCT_NAME, "PowerEdge 300/"),
NO_MATCH, NO_MATCH
} },
{ set_apm_ints, "IBM", { /* Allow interrupts during suspend on IBM laptops */
MATCH(DMI_SYS_VENDOR, "IBM"),
NO_MATCH, NO_MATCH, NO_MATCH
} },
{ set_apm_ints, "Dell Inspiron", { /* Allow interrupts during suspend on Dell Inspiron laptops*/
MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"),
MATCH(DMI_PRODUCT_NAME, "Inspiron 4000"),
......@@ -459,13 +495,11 @@ static __initdata struct dmi_blacklist dmi_blacklist[]={
MATCH(DMI_BIOS_VENDOR,"SystemSoft"),
MATCH(DMI_BIOS_VERSION,"Version R2.08")
} },
#if defined(CONFIG_SONYPI) || defined(CONFIG_SONYPI_MODULE)
{ sony_vaio_laptop, "Sony Vaio", { /* This is a Sony Vaio laptop */
MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
MATCH(DMI_PRODUCT_NAME, "PCG-"),
NO_MATCH, NO_MATCH,
} },
#endif
{ swab_apm_power_in_minutes, "Sony VAIO", { /* Handle problems with APM on Sony Vaio PCG-N505X(DE) */
MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies LTD"),
MATCH(DMI_BIOS_VERSION, "R0206H"),
......@@ -536,6 +570,11 @@ static __initdata struct dmi_blacklist dmi_blacklist[]={
MATCH(DMI_BIOS_VERSION,"L440GX0.86B.0125.P13"),
NO_MATCH, NO_MATCH
} },
{ broken_pirq, "l44GX Bios", { /* Bad $PIR */
MATCH(DMI_BIOS_VENDOR, "Intel Corporation"),
MATCH(DMI_BIOS_VERSION,"L440GX0.86B.0066.P07.9906041405"),
NO_MATCH, NO_MATCH
} },
/* Intel in disgiuse - In this case they can't hide and they don't run
too well either... */
......@@ -543,6 +582,37 @@ static __initdata struct dmi_blacklist dmi_blacklist[]={
MATCH(DMI_PRODUCT_NAME, "Dell PowerEdge 8450"),
NO_MATCH, NO_MATCH, NO_MATCH
} },
{ broken_acpi_Sx, "ASUS K7V-RM", { /* Bad ACPI Sx table */
MATCH(DMI_BIOS_VERSION,"ASUS K7V-RM ACPI BIOS Revision 1003A"),
MATCH(DMI_BOARD_NAME, "<K7V-RM>"),
NO_MATCH, NO_MATCH
} },
{ broken_toshiba_keyboard, "Toshiba Satellite 4030cdt", { /* Keyboard generates spurious repeats */
MATCH(DMI_PRODUCT_NAME, "S4030CDT/4.3"),
NO_MATCH, NO_MATCH, NO_MATCH
} },
{ init_ints_after_s1, "Toshiba Satellite 4030cdt", { /* Reinitialization of 8259 is needed after S1 resume */
MATCH(DMI_PRODUCT_NAME, "S4030CDT/4.3"),
NO_MATCH, NO_MATCH, NO_MATCH
} },
{ print_if_true, KERN_WARNING "IBM T23 - BIOS 1.03b+ and controller firmware 1.02+ may be needed for Linux APM.", {
MATCH(DMI_SYS_VENDOR, "IBM"),
MATCH(DMI_BIOS_VERSION, "1AET38WW (1.01b)"),
NO_MATCH, NO_MATCH
} },
/*
* Generic per vendor APM settings
*/
{ set_apm_ints, "IBM", { /* Allow interrupts during suspend on IBM laptops */
MATCH(DMI_SYS_VENDOR, "IBM"),
NO_MATCH, NO_MATCH, NO_MATCH
} },
{ NULL, }
};
......
......@@ -487,6 +487,13 @@ static struct ioctl32_list ioctl32_handler_table[] = {
IOCTL32_HANDLER(SIOCADDRT, routing_ioctl),
IOCTL32_HANDLER(SIOCDELRT, routing_ioctl),
IOCTL32_HANDLER(SIOCBONDENSLAVE, bond_ioctl),
IOCTL32_HANDLER(SIOCBONDRELEASE, bond_ioctl),
IOCTL32_HANDLER(SIOCBONDSETHWADDR, bond_ioctl),
IOCTL32_HANDLER(SIOCBONDSLAVEINFOQUERY, bond_ioctl),
IOCTL32_HANDLER(SIOCBONDINFOQUERY, bond_ioctl),
IOCTL32_HANDLER(SIOCBONDCHANGEACTIVE, bond_ioctl),
IOCTL32_HANDLER(EXT2_IOC32_GETFLAGS, do_ext2_ioctl),
IOCTL32_HANDLER(EXT2_IOC32_SETFLAGS, do_ext2_ioctl),
IOCTL32_HANDLER(EXT2_IOC32_GETVERSION, do_ext2_ioctl),
......
/* $Id: ioctl32.c,v 1.127 2001/11/01 23:54:19 davem Exp $
/* $Id: ioctl32.c,v 1.131 2001/11/07 01:13:23 davem Exp $
* ioctl32.c: Conversion between 32bit and 64bit native ioctls.
*
* Copyright (C) 1997-2000 Jakub Jelinek (jakub@redhat.com)
......@@ -71,6 +71,7 @@
#include <asm/audioio.h>
#include <linux/ethtool.h>
#include <linux/mii.h>
#include <linux/if_bonding.h>
#include <asm/display7seg.h>
#include <asm/watchdog.h>
#include <asm/module.h>
......@@ -592,6 +593,58 @@ static int ethtool_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
return err;
}
static int bond_ioctl(unsigned long fd, unsigned int cmd, unsigned long arg)
{
struct ifreq ifr;
mm_segment_t old_fs;
int err, len;
u32 data;
if (copy_from_user(&ifr, (struct ifreq32 *)arg, sizeof(struct ifreq32)))
return -EFAULT;
ifr.ifr_data = (__kernel_caddr_t)get_free_page(GFP_KERNEL);
if (!ifr.ifr_data)
return -EAGAIN;
switch (cmd) {
case SIOCBONDENSLAVE:
case SIOCBONDRELEASE:
case SIOCBONDSETHWADDR:
case SIOCBONDCHANGEACTIVE:
len = IFNAMSIZ * sizeof(char);
break;
case SIOCBONDSLAVEINFOQUERY:
len = sizeof(struct ifslave);
break;
case SIOCBONDINFOQUERY:
len = sizeof(struct ifbond);
break;
default:
err = -EINVAL;
goto out;
};
__get_user(data, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_data));
if (copy_from_user(ifr.ifr_data, (char *)A(data), len)) {
err = -EFAULT;
goto out;
}
old_fs = get_fs();
set_fs (KERNEL_DS);
err = sys_ioctl (fd, cmd, (unsigned long)&ifr);
set_fs (old_fs);
if (!err) {
len = copy_to_user((char *)A(data), ifr.ifr_data, len);
if (len)
err = -EFAULT;
}
out:
free_page((unsigned long)ifr.ifr_data);
return err;
}
static inline int dev_ifsioc(unsigned int fd, unsigned int cmd, unsigned long arg)
{
struct ifreq ifr;
......@@ -4488,6 +4541,12 @@ HANDLE_IOCTL(SIOCGPPPVER, dev_ifsioc)
HANDLE_IOCTL(SIOCGIFTXQLEN, dev_ifsioc)
HANDLE_IOCTL(SIOCSIFTXQLEN, dev_ifsioc)
HANDLE_IOCTL(SIOCETHTOOL, ethtool_ioctl)
HANDLE_IOCTL(SIOCBONDENSLAVE, bond_ioctl)
HANDLE_IOCTL(SIOCBONDRELEASE, bond_ioctl)
HANDLE_IOCTL(SIOCBONDSETHWADDR, bond_ioctl)
HANDLE_IOCTL(SIOCBONDSLAVEINFOQUERY, bond_ioctl)
HANDLE_IOCTL(SIOCBONDINFOQUERY, bond_ioctl)
HANDLE_IOCTL(SIOCBONDCHANGEACTIVE, bond_ioctl)
HANDLE_IOCTL(SIOCADDRT, routing_ioctl)
HANDLE_IOCTL(SIOCDELRT, routing_ioctl)
/* Note SIOCRTMSG is no longer, so this is safe and * the user would have seen just an -EINVAL anyways. */
......
......@@ -40,6 +40,11 @@ if [ "$CONFIG_PCI" = "y" ]; then
bool ' Use suni PHY driver (155Mbps)' CONFIG_ATM_NICSTAR_USE_SUNI
bool ' Use IDT77015 PHY driver (25Mbps)' CONFIG_ATM_NICSTAR_USE_IDT77105
fi
tristate 'IDT 77252 (NICStAR II)' CONFIG_ATM_IDT77252
if [ "$CONFIG_ATM_IDT77252" != "n" ]; then
bool ' Receive ALL cells in raw queue' CONFIG_ATM_IDT77252_RCV_ALL
define_bool CONFIG_ATM_IDT77252_USE_SUNI y
fi
tristate 'Madge Ambassador (Collage PCI 155 Server)' CONFIG_ATM_AMBASSADOR
if [ "$CONFIG_ATM_AMBASSADOR" != "n" ]; then
bool ' Enable debugging messages' CONFIG_ATM_AMBASSADOR_DEBUG
......
......@@ -12,6 +12,7 @@ obj-y := atmdev_init.o
obj-$(CONFIG_ATM_ENI) += eni.o suni.o
obj-$(CONFIG_ATM_ZATM) += zatm.o uPD98402.o
obj-$(CONFIG_ATM_NICSTAR) += nicstar.o
obj-$(CONFIG_ATM_IDT77252) += idt77252.o
ifeq ($(CONFIG_ATM_NICSTAR_USE_SUNI),y)
obj-$(CONFIG_ATM_NICSTAR) += suni.o
......@@ -21,6 +22,10 @@ ifeq ($(CONFIG_ATM_NICSTAR_USE_IDT77105),y)
obj-$(CONFIG_ATM_NICSTAR) += idt77105.o
endif
ifeq ($(CONFIG_ATM_IDT77252_USE_SUNI),y)
obj-$(CONFIG_ATM_IDT77252) += suni.o
endif
obj-$(CONFIG_ATM_HORIZON) += horizon.o
obj-$(CONFIG_ATM_AMBASSADOR) += ambassador.o
obj-$(CONFIG_ATM_TCP) += atmtcp.o
......
......@@ -13,6 +13,9 @@ extern int zatm_detect(void);
#ifdef CONFIG_ATM_NICSTAR
extern int nicstar_detect(void);
#endif
#ifdef CONFIG_ATM_IDT77252
extern int idt77252_detect(void);
#endif
#ifdef CONFIG_ATM_AMBASSADOR
extern int amb_detect(void);
#endif
......@@ -47,6 +50,9 @@ int __init atmdev_init(void)
#ifdef CONFIG_ATM_NICSTAR
devs += nicstar_detect();
#endif
#ifdef CONFIG_ATM_IDT77252
devs += idt77252_detect();
#endif
#ifdef CONFIG_ATM_AMBASSADOR
devs += amb_detect();
#endif
......
/*******************************************************************
* ident "$Id: idt77252.c,v 1.1 2001/11/05 21:52:22 ecd Exp $"
*
* $Author: ecd $
* $Date: 2001/11/05 21:52:22 $
*
* Copyright (c) 2000 ATecoM GmbH
*
* The author may be reached at ecd@atecom.com.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
* NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 675 Mass Ave, Cambridge, MA 02139, USA.
*
*******************************************************************/
static char const rcsid[] =
"$Id: idt77252.c,v 1.1 2001/11/05 21:52:22 ecd Exp $";
#include <linux/module.h>
#include <linux/config.h>
#include <linux/pci.h>
#include <linux/skbuff.h>
#include <linux/kernel.h>
#include <linux/vmalloc.h>
#include <linux/netdevice.h>
#include <linux/atmdev.h>
#include <linux/atm.h>
#include <linux/delay.h>
#include <linux/init.h>
#include <linux/bitops.h>
#include <linux/wait.h>
#include <asm/semaphore.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include <asm/atomic.h>
#include <asm/byteorder.h>
#ifdef CONFIG_ATM_IDT77252_USE_SUNI
#include "suni.h"
#endif /* CONFIG_ATM_IDT77252_USE_SUNI */
#define DEBUG 1
#include "idt77252.h"
#include "idt77252_tables.h"
static unsigned int vpibits = 1;
#define CONFIG_ATM_IDT77252_SEND_IDLE 1
/*
* Debug HACKs.
*/
#define DEBUG_MODULE 1
#undef DEBUG_RAW_CELLS
#undef HAVE_EEPROM /* does not work, yet. */
#ifdef DEBUG
static unsigned long debug = DBG_GENERAL;
#endif
#define SAR_RX_DELAY (SAR_CFG_RXINT_NODELAY)
/*
* SCQ Handling.
*/
static struct scq_info *alloc_scq(struct idt77252_dev *, int);
static void free_scq(struct idt77252_dev *, struct scq_info *);
static int queue_skb(struct idt77252_dev *, struct vc_map *,
struct sk_buff *, int oam);
static void drain_scq(struct idt77252_dev *, struct vc_map *);
static unsigned long get_free_scd(struct idt77252_dev *, struct vc_map *);
static void fill_scd(struct idt77252_dev *, struct scq_info *, int);
/*
* FBQ Handling.
*/
static int push_rx_skb(struct idt77252_dev *,
struct sk_buff *, int queue);
static void recycle_rx_skb(struct idt77252_dev *, struct sk_buff *);
static void flush_rx_pool(struct idt77252_dev *, struct rx_pool *);
static void recycle_rx_pool_skb(struct idt77252_dev *,
struct rx_pool *);
static void add_rx_skb(struct idt77252_dev *, int queue,
unsigned int size, unsigned int count);
/*
* RSQ Handling.
*/
static int init_rsq(struct idt77252_dev *);
static void deinit_rsq(struct idt77252_dev *);
static void idt77252_rx(struct idt77252_dev *);
/*
* TSQ handling.
*/
static int init_tsq(struct idt77252_dev *);
static void deinit_tsq(struct idt77252_dev *);
static void idt77252_tx(struct idt77252_dev *);
/*
* ATM Interface.
*/
static void idt77252_dev_close(struct atm_dev *dev);
static int idt77252_open(struct atm_vcc *vcc, short vpi, int vci);
static void idt77252_close(struct atm_vcc *vcc);
static int idt77252_send(struct atm_vcc *vcc, struct sk_buff *skb);
static int idt77252_send_oam(struct atm_vcc *vcc, void *cell,
int flags);
static void idt77252_phy_put(struct atm_dev *dev, unsigned char value,
unsigned long addr);
static unsigned char idt77252_phy_get(struct atm_dev *dev, unsigned long addr);
static int idt77252_change_qos(struct atm_vcc *vcc, struct atm_qos *qos,
int flags);
static int idt77252_proc_read(struct atm_dev *dev, loff_t * pos,
char *page);
static void idt77252_interrupt(int irq, void *dev_id,
struct pt_regs *regs);
static void idt77252_softint(void *dev_id);
static struct atmdev_ops idt77252_ops =
{
idt77252_dev_close, /* dev_close */
idt77252_open, /* open */
idt77252_close, /* close */
NULL, /* ioctl */
NULL, /* getsockopt */
NULL, /* setsockopt */
idt77252_send, /* send */
NULL, /* sg_send */
idt77252_send_oam, /* send_oam */
idt77252_phy_put,
idt77252_phy_get,
NULL, /* feedback */
idt77252_change_qos,
NULL, /* free_rx_skb */
idt77252_proc_read /* proc_read */
};
static struct idt77252_dev *idt77252_chain = NULL;
static unsigned int idt77252_sram_write_errors = 0;
/*****************************************************************************/
/* */
/* I/O and Utility Bus */
/* */
/*****************************************************************************/
static void
waitfor_idle(struct idt77252_dev *card)
{
u32 stat;
stat = readl(SAR_REG_STAT);
while (stat & SAR_STAT_CMDBZ)
stat = readl(SAR_REG_STAT);
}
static u32
read_sram(struct idt77252_dev *card, unsigned long addr)
{
unsigned long flags;
u32 value;
spin_lock_irqsave(&card->cmd_lock, flags);
writel(SAR_CMD_READ_SRAM | (addr << 2), SAR_REG_CMD);
waitfor_idle(card);
value = readl(SAR_REG_DR0);
spin_unlock_irqrestore(&card->cmd_lock, flags);
return value;
}
static void
write_sram(struct idt77252_dev *card, unsigned long addr, u32 value)
{
unsigned long flags;
if ((idt77252_sram_write_errors == 0) &&
(((addr > card->tst[0] + card->tst_size - 2) &&
(addr < card->tst[0] + card->tst_size)) ||
((addr > card->tst[1] + card->tst_size - 2) &&
(addr < card->tst[1] + card->tst_size)))) {
printk("%s: ERROR: TST JMP section at %08lx written: %08x\n",
card->name, addr, value);
}
spin_lock_irqsave(&card->cmd_lock, flags);
writel(value, SAR_REG_DR0);
writel(SAR_CMD_WRITE_SRAM | (addr << 2), SAR_REG_CMD);
waitfor_idle(card);
spin_unlock_irqrestore(&card->cmd_lock, flags);
}
static u8
read_utility(void *dev, unsigned long ubus_addr)
{
struct idt77252_dev *card = dev;
unsigned long flags;
u8 value;
if (!card) {
printk("Error: No such device.\n");
return -1;
}
spin_lock_irqsave(&card->cmd_lock, flags);
writel(SAR_CMD_READ_UTILITY + ubus_addr, SAR_REG_CMD);
waitfor_idle(card);
value = readl(SAR_REG_DR0);
spin_unlock_irqrestore(&card->cmd_lock, flags);
return value;
}
static void
write_utility(void *dev, unsigned long ubus_addr, u8 value)
{
struct idt77252_dev *card = dev;
unsigned long flags;
if (!card) {
printk("Error: No such device.\n");
return;
}
spin_lock_irqsave(&card->cmd_lock, flags);
writel((u32) value, SAR_REG_DR0);
writel(SAR_CMD_WRITE_UTILITY + ubus_addr, SAR_REG_CMD);
waitfor_idle(card);
spin_unlock_irqrestore(&card->cmd_lock, flags);
}
#ifdef HAVE_EEPROM
static u32 rdsrtab[] =
{
SAR_GP_EECS | SAR_GP_EESCLK,
0,
SAR_GP_EESCLK, /* 0 */
0,
SAR_GP_EESCLK, /* 0 */
0,
SAR_GP_EESCLK, /* 0 */
0,
SAR_GP_EESCLK, /* 0 */
0,
SAR_GP_EESCLK, /* 0 */
SAR_GP_EEDO,
SAR_GP_EESCLK | SAR_GP_EEDO, /* 1 */
0,
SAR_GP_EESCLK, /* 0 */
SAR_GP_EEDO,
SAR_GP_EESCLK | SAR_GP_EEDO /* 1 */
};
static u32 wrentab[] =
{
SAR_GP_EECS | SAR_GP_EESCLK,
0,
SAR_GP_EESCLK, /* 0 */
0,
SAR_GP_EESCLK, /* 0 */
0,
SAR_GP_EESCLK, /* 0 */
0,
SAR_GP_EESCLK, /* 0 */
SAR_GP_EEDO,
SAR_GP_EESCLK | SAR_GP_EEDO, /* 1 */
SAR_GP_EEDO,
SAR_GP_EESCLK | SAR_GP_EEDO, /* 1 */
0,
SAR_GP_EESCLK, /* 0 */
0,
SAR_GP_EESCLK /* 0 */
};
static u32 rdtab[] =
{
SAR_GP_EECS | SAR_GP_EESCLK,
0,
SAR_GP_EESCLK, /* 0 */
0,
SAR_GP_EESCLK, /* 0 */
0,
SAR_GP_EESCLK, /* 0 */
0,
SAR_GP_EESCLK, /* 0 */
0,
SAR_GP_EESCLK, /* 0 */
0,
SAR_GP_EESCLK, /* 0 */
SAR_GP_EEDO,
SAR_GP_EESCLK | SAR_GP_EEDO, /* 1 */
SAR_GP_EEDO,
SAR_GP_EESCLK | SAR_GP_EEDO /* 1 */
};
static u32 wrtab[] =
{
SAR_GP_EECS | SAR_GP_EESCLK,
0,
SAR_GP_EESCLK, /* 0 */
0,
SAR_GP_EESCLK, /* 0 */
0,
SAR_GP_EESCLK, /* 0 */
0,
SAR_GP_EESCLK, /* 0 */
0,
SAR_GP_EESCLK, /* 0 */
0,
SAR_GP_EESCLK, /* 0 */
SAR_GP_EEDO,
SAR_GP_EESCLK | SAR_GP_EEDO, /* 1 */
0,
SAR_GP_EESCLK /* 0 */
};
static u32 clktab[] =
{
0,
SAR_GP_EESCLK,
0,
SAR_GP_EESCLK,
0,
SAR_GP_EESCLK,
0,
SAR_GP_EESCLK,
0,
SAR_GP_EESCLK,
0,
SAR_GP_EESCLK,
0,
SAR_GP_EESCLK,
0,
SAR_GP_EESCLK,
0
};
static u32
idt77252_read_gp(struct idt77252_dev *card)
{
u32 gp;
gp = readl(SAR_REG_GP);
#if 0
printk("RD: %s\n", gp & SAR_GP_EEDI ? "1" : "0");
#endif
return gp;
}
static void
idt77252_write_gp(struct idt77252_dev *card, u32 value)
{
unsigned long flags;
#if 0
printk("WR: %s %s %s\n", value & SAR_GP_EECS ? " " : "/CS",
value & SAR_GP_EESCLK ? "HIGH" : "LOW ",
value & SAR_GP_EEDO ? "1" : "0");
#endif
spin_lock_irqsave(&card->cmd_lock, flags);
waitfor_idle(card);
writel(value, SAR_REG_GP);
spin_unlock_irqrestore(&card->cmd_lock, flags);
}
static u8
idt77252_eeprom_read_status(struct idt77252_dev *card)
{
u8 byte;
u32 gp;
int i, j;
gp = idt77252_read_gp(card) & ~(SAR_GP_EESCLK|SAR_GP_EECS|SAR_GP_EEDO);
for (i = 0; i < sizeof(rdsrtab)/sizeof(rdsrtab[0]); i++) {
idt77252_write_gp(card, gp | rdsrtab[i]);
udelay(5);
}
idt77252_write_gp(card, gp | SAR_GP_EECS);
udelay(5);
byte = 0;
for (i = 0, j = 0; i < 8; i++) {
byte <<= 1;
idt77252_write_gp(card, gp | clktab[j++]);
udelay(5);
byte |= idt77252_read_gp(card) & SAR_GP_EEDI ? 1 : 0;
idt77252_write_gp(card, gp | clktab[j++]);
udelay(5);
}
idt77252_write_gp(card, gp | SAR_GP_EECS);
udelay(5);
return byte;
}
static u8
idt77252_eeprom_read_byte(struct idt77252_dev *card, u8 offset)
{
u8 byte;
u32 gp;
int i, j;
gp = idt77252_read_gp(card) & ~(SAR_GP_EESCLK|SAR_GP_EECS|SAR_GP_EEDO);
for (i = 0; i < sizeof(rdtab)/sizeof(rdtab[0]); i++) {
idt77252_write_gp(card, gp | rdtab[i]);
udelay(5);
}
idt77252_write_gp(card, gp | SAR_GP_EECS);
udelay(5);
for (i = 0, j = 0; i < 8; i++) {
idt77252_write_gp(card, gp | clktab[j++] |
(offset & 1 ? SAR_GP_EEDO : 0));
udelay(5);
idt77252_write_gp(card, gp | clktab[j++] |
(offset & 1 ? SAR_GP_EEDO : 0));
udelay(5);
offset >>= 1;
}
idt77252_write_gp(card, gp | SAR_GP_EECS);
udelay(5);
byte = 0;
for (i = 0, j = 0; i < 8; i++) {
byte <<= 1;
idt77252_write_gp(card, gp | clktab[j++]);
udelay(5);
byte |= idt77252_read_gp(card) & SAR_GP_EEDI ? 1 : 0;
idt77252_write_gp(card, gp | clktab[j++]);
udelay(5);
}
idt77252_write_gp(card, gp | SAR_GP_EECS);
udelay(5);
return byte;
}
static void
idt77252_eeprom_write_byte(struct idt77252_dev *card, u8 offset, u8 data)
{
u32 gp;
int i, j;
gp = idt77252_read_gp(card) & ~(SAR_GP_EESCLK|SAR_GP_EECS|SAR_GP_EEDO);
for (i = 0; i < sizeof(wrentab)/sizeof(wrentab[0]); i++) {
idt77252_write_gp(card, gp | wrentab[i]);
udelay(5);
}
idt77252_write_gp(card, gp | SAR_GP_EECS);
udelay(5);
for (i = 0; i < sizeof(wrtab)/sizeof(wrtab[0]); i++) {
idt77252_write_gp(card, gp | wrtab[i]);
udelay(5);
}
idt77252_write_gp(card, gp | SAR_GP_EECS);
udelay(5);
for (i = 0, j = 0; i < 8; i++) {
idt77252_write_gp(card, gp | clktab[j++] |
(offset & 1 ? SAR_GP_EEDO : 0));
udelay(5);
idt77252_write_gp(card, gp | clktab[j++] |
(offset & 1 ? SAR_GP_EEDO : 0));
udelay(5);
offset >>= 1;
}
idt77252_write_gp(card, gp | SAR_GP_EECS);
udelay(5);
for (i = 0, j = 0; i < 8; i++) {
idt77252_write_gp(card, gp | clktab[j++] |
(data & 1 ? SAR_GP_EEDO : 0));
udelay(5);
idt77252_write_gp(card, gp | clktab[j++] |
(data & 1 ? SAR_GP_EEDO : 0));
udelay(5);
data >>= 1;
}
idt77252_write_gp(card, gp | SAR_GP_EECS);
udelay(5);
}
static void
idt77252_eeprom_init(struct idt77252_dev *card)
{
u32 gp;
gp = idt77252_read_gp(card) & ~(SAR_GP_EESCLK|SAR_GP_EECS|SAR_GP_EEDO);
idt77252_write_gp(card, gp | SAR_GP_EECS | SAR_GP_EESCLK);
udelay(5);
idt77252_write_gp(card, gp | SAR_GP_EECS);
udelay(5);
idt77252_write_gp(card, gp | SAR_GP_EECS | SAR_GP_EESCLK);
udelay(5);
idt77252_write_gp(card, gp | SAR_GP_EECS);
udelay(5);
}
#endif /* HAVE_EEPROM */
#ifdef DEBUG
static void
dump_tct(struct idt77252_dev *card, int index)
{
unsigned long tct;
int i;
tct = (unsigned long) (card->tct_base + index * SAR_SRAM_TCT_SIZE);
printk("%s: TCT %x:", card->name, index);
for (i = 0; i < 8; i++) {
printk(" %08x", read_sram(card, tct + i));
}
printk("\n");
}
static void
idt77252_tx_dump(struct idt77252_dev *card)
{
struct atm_vcc *vcc;
struct vc_map *vc;
int i;
printk("%s\n", __FUNCTION__);
for (i = 0; i < card->tct_size; i++) {
vc = card->vcs[i];
if (!vc)
continue;
vcc = NULL;
if (vc->rx_vcc)
vcc = vc->rx_vcc;
else if (vc->tx_vcc)
vcc = vc->tx_vcc;
if (!vcc)
continue;
printk("%s: Connection %d:\n", card->name, vc->index);
dump_tct(card, vc->index);
}
}
#endif
/*****************************************************************************/
/* */
/* SCQ Handling */
/* */
/*****************************************************************************/
static int
sb_pool_add(struct idt77252_dev *card, struct sk_buff *skb, int queue)
{
struct sb_pool *pool = &card->sbpool[queue];
int index;
index = pool->index;
while (pool->skb[index]) {
index = (index + 1) & FBQ_MASK;
if (index == pool->index)
return -ENOBUFS;
}
pool->skb[index] = skb;
IDT77252_PRV_POOL(skb) = POOL_HANDLE(queue, index);
pool->index = (index + 1) & FBQ_MASK;
return 0;
}
static void
sb_pool_remove(struct idt77252_dev *card, struct sk_buff *skb)
{
unsigned int queue, index;
u32 handle;
handle = IDT77252_PRV_POOL(skb);
queue = POOL_QUEUE(handle);
if (queue > 3)
return;
index = POOL_INDEX(handle);
if (index > FBQ_SIZE - 1)
return;
card->sbpool[queue].skb[index] = NULL;
}
static struct sk_buff *
sb_pool_skb(struct idt77252_dev *card, u32 handle)
{
unsigned int queue, index;
queue = POOL_QUEUE(handle);
if (queue > 3)
return NULL;
index = POOL_INDEX(handle);
if (index > FBQ_SIZE - 1)
return NULL;
return card->sbpool[queue].skb[index];
}
static struct scq_info *
alloc_scq(struct idt77252_dev *card, int class)
{
struct scq_info *scq;
scq = (struct scq_info *) kmalloc(sizeof(struct scq_info), GFP_KERNEL);
if (!scq)
return NULL;
memset(scq, 0, sizeof(struct scq_info));
scq->base = pci_alloc_consistent(card->pcidev, SCQ_SIZE,
&scq->paddr);
if (scq->base == NULL) {
kfree(scq);
return NULL;
}
memset(scq->base, 0, SCQ_SIZE);
scq->next = scq->base;
scq->last = scq->base + (SCQ_ENTRIES - 1);
atomic_set(&scq->used, 0);
spin_lock_init(&scq->lock);
spin_lock_init(&scq->skblock);
skb_queue_head_init(&scq->transmit);
skb_queue_head_init(&scq->pending);
TXPRINTK("idt77252: SCQ: base 0x%p, next 0x%p, last 0x%p, paddr %08x\n",
scq->base, scq->next, scq->last, scq->paddr);
return scq;
}
static void
free_scq(struct idt77252_dev *card, struct scq_info *scq)
{
struct sk_buff *skb;
struct atm_vcc *vcc;
pci_free_consistent(card->pcidev, SCQ_SIZE,
scq->base, scq->paddr);
while ((skb = skb_dequeue(&scq->transmit))) {
pci_unmap_single(card->pcidev, IDT77252_PRV_PADDR(skb),
skb->len, PCI_DMA_TODEVICE);
vcc = ATM_SKB(skb)->vcc;
if (vcc->pop)
vcc->pop(vcc, skb);
else
dev_kfree_skb(skb);
}
while ((skb = skb_dequeue(&scq->pending))) {
pci_unmap_single(card->pcidev, IDT77252_PRV_PADDR(skb),
skb->len, PCI_DMA_TODEVICE);
vcc = ATM_SKB(skb)->vcc;
if (vcc->pop)
vcc->pop(vcc, skb);
else
dev_kfree_skb(skb);
}
kfree(scq);
}
static int
push_on_scq(struct idt77252_dev *card, struct vc_map *vc, struct sk_buff *skb)
{
struct scq_info *scq = vc->scq;
unsigned long flags;
struct scqe *tbd;
int entries;
TXPRINTK("%s: SCQ: next 0x%p\n", card->name, scq->next);
atomic_inc(&scq->used);
entries = atomic_read(&scq->used);
if (entries > (SCQ_ENTRIES - 1)) {
atomic_dec(&scq->used);
goto out;
}
skb_queue_tail(&scq->transmit, skb);
spin_lock_irqsave(&vc->lock, flags);
if (vc->estimator) {
struct atm_vcc *vcc = vc->tx_vcc;
vc->estimator->cells += (skb->len + 47) / 48;
if (atomic_read(&vcc->tx_inuse) > (vcc->sk->sndbuf >> 1)) {
u32 cps = vc->estimator->maxcps;
vc->estimator->cps = cps;
vc->estimator->avcps = cps << 5;
if (vc->lacr < vc->init_er) {
vc->lacr = vc->init_er;
writel(TCMDQ_LACR | (vc->lacr << 16) |
vc->index, SAR_REG_TCMDQ);
}
}
}
spin_unlock_irqrestore(&vc->lock, flags);
tbd = &IDT77252_PRV_TBD(skb);
spin_lock_irqsave(&scq->lock, flags);
scq->next->word_1 = cpu_to_le32(tbd->word_1 |
SAR_TBD_TSIF | SAR_TBD_GTSI);
scq->next->word_2 = cpu_to_le32(tbd->word_2);
scq->next->word_3 = cpu_to_le32(tbd->word_3);
scq->next->word_4 = cpu_to_le32(tbd->word_4);
if (scq->next == scq->last)
scq->next = scq->base;
else
scq->next++;
write_sram(card, scq->scd,
scq->paddr +
(u32)((unsigned long)scq->next - (unsigned long)scq->base));
spin_unlock_irqrestore(&scq->lock, flags);
scq->trans_start = jiffies;
if (test_and_clear_bit(VCF_IDLE, &vc->flags)) {
writel(TCMDQ_START_LACR | (vc->lacr << 16) | vc->index,
SAR_REG_TCMDQ);
}
TXPRINTK("%d entries in SCQ used (push).\n", atomic_read(&scq->used));
XPRINTK("%s: SCQ (after push %2d) head = 0x%x, next = 0x%p.\n",
card->name, atomic_read(&scq->used),
read_sram(card, scq->scd + 1), scq->next);
return 0;
out:
if (jiffies - scq->trans_start > HZ) {
printk("%s: Error pushing TBD for %d.%d\n",
card->name, vc->tx_vcc->vpi, vc->tx_vcc->vci);
idt77252_tx_dump(card);
scq->trans_start = jiffies;
}
return -ENOBUFS;
}
static void
drain_scq(struct idt77252_dev *card, struct vc_map *vc)
{
struct scq_info *scq = vc->scq;
struct sk_buff *skb;
struct atm_vcc *vcc;
TXPRINTK("%s: SCQ (before drain %2d) next = 0x%p.\n",
card->name, atomic_read(&scq->used), scq->next);
skb = skb_dequeue(&scq->transmit);
if (skb) {
TXPRINTK("%s: freeing skb at %p.\n", card->name, skb);
pci_unmap_single(card->pcidev, IDT77252_PRV_PADDR(skb),
skb->len, PCI_DMA_TODEVICE);
vcc = ATM_SKB(skb)->vcc;
if (vcc->pop)
vcc->pop(vcc, skb);
else
dev_kfree_skb(skb);
atomic_inc(&vcc->stats->tx);
}
atomic_dec(&scq->used);
spin_lock(&scq->skblock);
while ((skb = skb_dequeue(&scq->pending))) {
if (push_on_scq(card, vc, skb)) {
skb_queue_head(&vc->scq->pending, skb);
break;
}
}
spin_unlock(&scq->skblock);
}
static int
queue_skb(struct idt77252_dev *card, struct vc_map *vc,
struct sk_buff *skb, int oam)
{
struct atm_vcc *vcc;
struct scqe *tbd;
unsigned long flags;
int error;
int aal;
if (skb->len == 0) {
printk("%s: invalid skb->len (%d)\n", card->name, skb->len);
return -EINVAL;
}
TXPRINTK("%s: Sending %d bytes of data.\n",
card->name, skb->len);
tbd = &IDT77252_PRV_TBD(skb);
vcc = ATM_SKB(skb)->vcc;
IDT77252_PRV_PADDR(skb) = pci_map_single(card->pcidev, skb->data,
skb->len, PCI_DMA_TODEVICE);
error = -EINVAL;
if (oam) {
if (skb->len != 52)
goto errout;
tbd->word_1 = SAR_TBD_OAM | ATM_CELL_PAYLOAD | SAR_TBD_EPDU;
tbd->word_2 = IDT77252_PRV_PADDR(skb) + 4;
tbd->word_3 = 0x00000000;
tbd->word_4 = (skb->data[0] << 24) | (skb->data[1] << 16) |
(skb->data[2] << 8) | (skb->data[3] << 0);
if (test_bit(VCF_RSV, &vc->flags))
vc = card->vcs[0];
goto done;
}
if (test_bit(VCF_RSV, &vc->flags)) {
printk("%s: Trying to transmit on reserved VC\n", card->name);
goto errout;
}
aal = vcc->qos.aal;
switch (aal) {
case ATM_AAL0:
case ATM_AAL34:
if (skb->len > 52)
goto errout;
if (aal == ATM_AAL0)
tbd->word_1 = SAR_TBD_EPDU | SAR_TBD_AAL0 |
ATM_CELL_PAYLOAD;
else
tbd->word_1 = SAR_TBD_EPDU | SAR_TBD_AAL34 |
ATM_CELL_PAYLOAD;
tbd->word_2 = IDT77252_PRV_PADDR(skb) + 4;
tbd->word_3 = 0x00000000;
tbd->word_4 = (skb->data[0] << 24) | (skb->data[1] << 16) |
(skb->data[2] << 8) | (skb->data[3] << 0);
break;
case ATM_AAL5:
tbd->word_1 = SAR_TBD_EPDU | SAR_TBD_AAL5 | skb->len;
tbd->word_2 = IDT77252_PRV_PADDR(skb);
tbd->word_3 = skb->len;
tbd->word_4 = (vcc->vpi << SAR_TBD_VPI_SHIFT) |
(vcc->vci << SAR_TBD_VCI_SHIFT);
break;
case ATM_AAL1:
case ATM_AAL2:
default:
printk("%s: Traffic type not supported.\n", card->name);
error = -EPROTONOSUPPORT;
goto errout;
}
done:
spin_lock_irqsave(&vc->scq->skblock, flags);
skb_queue_tail(&vc->scq->pending, skb);
while ((skb = skb_dequeue(&vc->scq->pending))) {
if (push_on_scq(card, vc, skb)) {
skb_queue_head(&vc->scq->pending, skb);
break;
}
}
spin_unlock_irqrestore(&vc->scq->skblock, flags);
return 0;
errout:
pci_unmap_single(card->pcidev, IDT77252_PRV_PADDR(skb),
skb->len, PCI_DMA_TODEVICE);
return error;
}
static unsigned long
get_free_scd(struct idt77252_dev *card, struct vc_map *vc)
{
int i;
for (i = 0; i < card->scd_size; i++) {
if (!card->scd2vc[i]) {
card->scd2vc[i] = vc;
vc->scd_index = i;
return card->scd_base + i * SAR_SRAM_SCD_SIZE;
}
}
return 0;
}
static void
fill_scd(struct idt77252_dev *card, struct scq_info *scq, int class)
{
write_sram(card, scq->scd, scq->paddr);
write_sram(card, scq->scd + 1, 0x00000000);
write_sram(card, scq->scd + 2, 0xffffffff);
write_sram(card, scq->scd + 3, 0x00000000);
}
static void
clear_scd(struct idt77252_dev *card, struct scq_info *scq, int class)
{
return;
}
/*****************************************************************************/
/* */
/* RSQ Handling */
/* */
/*****************************************************************************/
static int
init_rsq(struct idt77252_dev *card)
{
struct rsq_entry *rsqe;
card->rsq.base = pci_alloc_consistent(card->pcidev, RSQSIZE,
&card->rsq.paddr);
if (card->rsq.base == NULL) {
printk("%s: can't allocate RSQ.\n", card->name);
return -1;
}
memset(card->rsq.base, 0, RSQSIZE);
card->rsq.last = card->rsq.base + RSQ_NUM_ENTRIES - 1;
card->rsq.next = card->rsq.last;
for (rsqe = card->rsq.base; rsqe <= card->rsq.last; rsqe++)
rsqe->word_4 = 0;
writel((unsigned long) card->rsq.last - (unsigned long) card->rsq.base,
SAR_REG_RSQH);
writel(card->rsq.paddr, SAR_REG_RSQB);
IPRINTK("%s: RSQ base at 0x%lx (0x%x).\n", card->name,
(unsigned long) card->rsq.base,
readl(SAR_REG_RSQB));
IPRINTK("%s: RSQ head = 0x%x, base = 0x%x, tail = 0x%x.\n",
card->name,
readl(SAR_REG_RSQH),
readl(SAR_REG_RSQB),
readl(SAR_REG_RSQT));
return 0;
}
static void
deinit_rsq(struct idt77252_dev *card)
{
pci_free_consistent(card->pcidev, RSQSIZE,
card->rsq.base, card->rsq.paddr);
}
static void
dequeue_rx(struct idt77252_dev *card, struct rsq_entry *rsqe)
{
struct atm_vcc *vcc;
struct sk_buff *skb;
struct rx_pool *rpp;
struct vc_map *vc;
u32 header, vpi, vci;
u32 stat;
int i;
stat = le32_to_cpu(rsqe->word_4);
if (stat & SAR_RSQE_IDLE) {
RXPRINTK("%s: message about inactive connection.\n",
card->name);
return;
}
skb = sb_pool_skb(card, le32_to_cpu(rsqe->word_2));
if (skb == NULL) {
printk("%s: NULL skb in %s, rsqe: %08x %08x %08x %08x\n",
card->name, __FUNCTION__,
le32_to_cpu(rsqe->word_1), le32_to_cpu(rsqe->word_2),
le32_to_cpu(rsqe->word_3), le32_to_cpu(rsqe->word_4));
return;
}
header = le32_to_cpu(rsqe->word_1);
vpi = (header >> 16) & 0x00ff;
vci = (header >> 0) & 0xffff;
RXPRINTK("%s: SDU for %d.%d received in buffer 0x%p (data 0x%p).\n",
card->name, vpi, vci, skb, skb->data);
if ((vpi >= (1 << card->vpibits)) || (vci != (vci & card->vcimask))) {
printk("%s: SDU received for out-of-range vc %u.%u\n",
card->name, vpi, vci);
recycle_rx_skb(card, skb);
return;
}
vc = card->vcs[VPCI2VC(card, vpi, vci)];
if (!vc || !test_bit(VCF_RX, &vc->flags)) {
printk("%s: SDU received on non RX vc %u.%u\n",
card->name, vpi, vci);
recycle_rx_skb(card, skb);
return;
}
vcc = vc->rx_vcc;
pci_dma_sync_single(card->pcidev, IDT77252_PRV_PADDR(skb),
skb->end - skb->data, PCI_DMA_FROMDEVICE);
if ((vcc->qos.aal == ATM_AAL0) ||
(vcc->qos.aal == ATM_AAL34)) {
struct sk_buff *sb;
unsigned char *cell;
u32 aal0;
cell = skb->data;
for (i = (stat & SAR_RSQE_CELLCNT); i; i--) {
if ((sb = dev_alloc_skb(64)) == NULL) {
printk("%s: Can't allocate buffers for aal0.\n",
card->name);
atomic_add(i, &vcc->stats->rx_drop);
break;
}
if (!atm_charge(vcc, sb->truesize)) {
RXPRINTK("%s: atm_charge() dropped aal0 packets.\n",
card->name);
atomic_add(i - 1, &vcc->stats->rx_drop);
dev_kfree_skb(sb);
break;
}
aal0 = (vpi << ATM_HDR_VPI_SHIFT) |
(vci << ATM_HDR_VCI_SHIFT);
aal0 |= (stat & SAR_RSQE_EPDU) ? 0x00000002 : 0;
aal0 |= (stat & SAR_RSQE_CLP) ? 0x00000001 : 0;
*((u32 *) sb->data) = aal0;
skb_put(sb, sizeof(u32));
memcpy(skb_put(sb, ATM_CELL_PAYLOAD),
cell, ATM_CELL_PAYLOAD);
ATM_SKB(sb)->vcc = vcc;
sb->stamp = xtime;
vcc->push(vcc, sb);
atomic_inc(&vcc->stats->rx);
cell += ATM_CELL_PAYLOAD;
}
recycle_rx_skb(card, skb);
return;
}
if (vcc->qos.aal != ATM_AAL5) {
printk("%s: Unexpected AAL type in dequeue_rx(): %d.\n",
card->name, vcc->qos.aal);
recycle_rx_skb(card, skb);
return;
}
skb->len = (stat & SAR_RSQE_CELLCNT) * ATM_CELL_PAYLOAD;
rpp = &vc->rcv.rx_pool;
rpp->len += skb->len;
if (!rpp->count++)
rpp->first = skb;
*rpp->last = skb;
rpp->last = &IDT77252_PRV_NEXT(skb);
if (stat & SAR_RSQE_EPDU) {
unsigned char *l1l2;
unsigned int len;
l1l2 = (unsigned char *) ((unsigned long) skb->data + skb->len - 6);
len = (l1l2[0] << 8) | l1l2[1];
len = len ? len : 0x10000;
RXPRINTK("%s: PDU has %d bytes.\n", card->name, len);
if ((len + 8 > rpp->len) || (len + (47 + 8) < rpp->len)) {
RXPRINTK("%s: AAL5 PDU size mismatch: %d != %d. "
"(CDC: %08x)\n",
card->name, len, rpp->len, readl(SAR_REG_CDC));
recycle_rx_pool_skb(card, rpp);
atomic_inc(&vcc->stats->rx_err);
return;
}
if (stat & SAR_RSQE_CRC) {
RXPRINTK("%s: AAL5 CRC error.\n", card->name);
recycle_rx_pool_skb(card, rpp);
atomic_inc(&vcc->stats->rx_err);
return;
}
if (rpp->count > 1) {
struct sk_buff *sb;
skb = dev_alloc_skb(rpp->len);
if (!skb) {
RXPRINTK("%s: Can't alloc RX skb.\n",
card->name);
recycle_rx_pool_skb(card, rpp);
atomic_inc(&vcc->stats->rx_err);
return;
}
if (!atm_charge(vcc, skb->truesize)) {
recycle_rx_pool_skb(card, rpp);
dev_kfree_skb(skb);
return;
}
sb = rpp->first;
for (i = 0; i < rpp->count; i++) {
memcpy(skb_put(skb, sb->len),
sb->data, sb->len);
sb = IDT77252_PRV_NEXT(sb);
}
recycle_rx_pool_skb(card, rpp);
skb_trim(skb, len);
ATM_SKB(skb)->vcc = vcc;
skb->stamp = xtime;
vcc->push(vcc, skb);
atomic_inc(&vcc->stats->rx);
return;
}
flush_rx_pool(card, rpp);
if (!atm_charge(vcc, skb->truesize)) {
recycle_rx_skb(card, skb);
return;
}
pci_unmap_single(card->pcidev, IDT77252_PRV_PADDR(skb),
skb->end - skb->data, PCI_DMA_FROMDEVICE);
sb_pool_remove(card, skb);
skb_trim(skb, len);
ATM_SKB(skb)->vcc = vcc;
skb->stamp = xtime;
vcc->push(vcc, skb);
atomic_inc(&vcc->stats->rx);
if (skb->truesize > SAR_FB_SIZE_3)
add_rx_skb(card, 3, SAR_FB_SIZE_3, 1);
else if (skb->truesize > SAR_FB_SIZE_2)
add_rx_skb(card, 2, SAR_FB_SIZE_2, 1);
else if (skb->truesize > SAR_FB_SIZE_1)
add_rx_skb(card, 1, SAR_FB_SIZE_1, 1);
else
add_rx_skb(card, 0, SAR_FB_SIZE_0, 1);
return;
}
}
static void
idt77252_rx(struct idt77252_dev *card)
{
struct rsq_entry *rsqe;
if (card->rsq.next == card->rsq.last)
rsqe = card->rsq.base;
else
rsqe = card->rsq.next + 1;
if (!(le32_to_cpu(rsqe->word_4) & SAR_RSQE_VALID)) {
RXPRINTK("%s: no entry in RSQ.\n", card->name);
return;
}
do {
dequeue_rx(card, rsqe);
rsqe->word_4 = 0;
card->rsq.next = rsqe;
if (card->rsq.next == card->rsq.last)
rsqe = card->rsq.base;
else
rsqe = card->rsq.next + 1;
} while (le32_to_cpu(rsqe->word_4) & SAR_RSQE_VALID);
writel((unsigned long) card->rsq.next - (unsigned long) card->rsq.base,
SAR_REG_RSQH);
}
static void
idt77252_rx_raw(struct idt77252_dev *card)
{
struct sk_buff *queue;
u32 head, tail;
struct atm_vcc *vcc;
struct vc_map *vc;
struct sk_buff *sb;
if (card->raw_cell_head == NULL) {
u32 handle = le32_to_cpu(*(card->raw_cell_hnd + 1));
card->raw_cell_head = sb_pool_skb(card, handle);
}
queue = card->raw_cell_head;
if (!queue)
return;
head = IDT77252_PRV_PADDR(queue) + (queue->data - queue->head - 16);
tail = readl(SAR_REG_RAWCT);
pci_dma_sync_single(card->pcidev, IDT77252_PRV_PADDR(queue),
queue->end - queue->head - 16, PCI_DMA_FROMDEVICE);
while (head != tail) {
unsigned int vpi, vci, pti;
u32 header;
header = le32_to_cpu(*(u32 *) &queue->data[0]);
vpi = (header & ATM_HDR_VPI_MASK) >> ATM_HDR_VPI_SHIFT;
vci = (header & ATM_HDR_VCI_MASK) >> ATM_HDR_VCI_SHIFT;
pti = (header & ATM_HDR_PTI_MASK) >> ATM_HDR_PTI_SHIFT;
#ifdef DEBUG_RAW_CELLS
{
int i;
printk("%s: raw cell %x.%02x.%04x.%x.%x\n",
card->name, (header >> 28) & 0x000f,
(header >> 20) & 0x00ff,
(header >> 4) & 0xffff,
(header >> 1) & 0x0007,
(header >> 0) & 0x0001);
for (i = 16; i < 64; i++)
printk(" %02x", queue->data[i]);
printk("\n");
}
#endif
if (vpi >= (1<<card->vpibits) || vci >= (1<<card->vcibits)) {
#ifdef DEBUG_RAW_CELLS
printk("%s: SDU received for out-of-range vc %u.%u\n",
card->name, vpi, vci);
#endif
goto drop;
}
vc = card->vcs[VPCI2VC(card, vpi, vci)];
if (!vc || !test_bit(VCF_RX, &vc->flags)) {
#ifdef DEBUG_RAW_CELLS
printk("%s: SDU received on non RX vc %u.%u\n",
card->name, vpi, vci);
#endif
goto drop;
}
vcc = vc->rx_vcc;
if (vcc->qos.aal != ATM_AAL0) {
#ifdef DEBUG_RAW_CELLS
printk("%s: raw cell for non AAL0 vc %u.%u\n",
card->name, vpi, vci);
#endif
atomic_inc(&vcc->stats->rx_drop);
goto drop;
}
if ((sb = dev_alloc_skb(64)) == NULL) {
printk("%s: Can't allocate buffers for AAL0.\n",
card->name);
atomic_inc(&vcc->stats->rx_err);
goto drop;
}
if ((vcc->sk != NULL) && !atm_charge(vcc, sb->truesize)) {
RXPRINTK("%s: atm_charge() dropped AAL0 packets.\n",
card->name);
dev_kfree_skb(sb);
goto drop;
}
*((u32 *) sb->data) = header;
skb_put(sb, sizeof(u32));
memcpy(skb_put(sb, ATM_CELL_PAYLOAD), &(queue->data[16]),
ATM_CELL_PAYLOAD);
ATM_SKB(sb)->vcc = vcc;
sb->stamp = xtime;
vcc->push(vcc, sb);
atomic_inc(&vcc->stats->rx);
drop:
skb_pull(queue, 64);
head = IDT77252_PRV_PADDR(queue)
+ (queue->data - queue->head - 16);
if (queue->len < 128) {
struct sk_buff *next;
u32 handle;
head = le32_to_cpu(*(u32 *) &queue->data[0]);
handle = le32_to_cpu(*(u32 *) &queue->data[4]);
next = sb_pool_skb(card, handle);
recycle_rx_skb(card, queue);
if (next) {
card->raw_cell_head = next;
queue = card->raw_cell_head;
pci_dma_sync_single(card->pcidev,
IDT77252_PRV_PADDR(queue),
queue->end - queue->data,
PCI_DMA_FROMDEVICE);
} else {
card->raw_cell_head = NULL;
printk("%s: raw cell queue overrun\n",
card->name);
break;
}
}
}
}
/*****************************************************************************/
/* */
/* TSQ Handling */
/* */
/*****************************************************************************/
static int
init_tsq(struct idt77252_dev *card)
{
struct tsq_entry *tsqe;
card->tsq.base = pci_alloc_consistent(card->pcidev, RSQSIZE,
&card->tsq.paddr);
if (card->tsq.base == NULL) {
printk("%s: can't allocate TSQ.\n", card->name);
return -1;
}
memset(card->tsq.base, 0, TSQSIZE);
card->tsq.last = card->tsq.base + TSQ_NUM_ENTRIES - 1;
card->tsq.next = card->tsq.last;
for (tsqe = card->tsq.base; tsqe <= card->tsq.last; tsqe++)
tsqe->word_2 = cpu_to_le32(SAR_TSQE_INVALID);
writel(card->tsq.paddr, SAR_REG_TSQB);
writel((unsigned long) card->tsq.next - (unsigned long) card->tsq.base,
SAR_REG_TSQH);
return 0;
}
static void
deinit_tsq(struct idt77252_dev *card)
{
pci_free_consistent(card->pcidev, TSQSIZE,
card->tsq.base, card->tsq.paddr);
}
static void
idt77252_tx(struct idt77252_dev *card)
{
struct tsq_entry *tsqe;
unsigned int vpi, vci;
struct vc_map *vc;
u32 conn, stat;
if (card->tsq.next == card->tsq.last)
tsqe = card->tsq.base;
else
tsqe = card->tsq.next + 1;
TXPRINTK("idt77252_tx: tsq %p: base %p, next %p, last %p\n", tsqe,
card->tsq.base, card->tsq.next, card->tsq.last);
TXPRINTK("idt77252_tx: tsqb %08x, tsqt %08x, tsqh %08x, \n",
readl(SAR_REG_TSQB),
readl(SAR_REG_TSQT),
readl(SAR_REG_TSQH));
stat = le32_to_cpu(tsqe->word_2);
if (stat & SAR_TSQE_INVALID)
return;
do {
TXPRINTK("tsqe: 0x%p [0x%08x 0x%08x]\n", tsqe,
le32_to_cpu(tsqe->word_1),
le32_to_cpu(tsqe->word_2));
switch (stat & SAR_TSQE_TYPE) {
case SAR_TSQE_TYPE_TIMER:
TXPRINTK("%s: Timer RollOver detected.\n", card->name);
break;
case SAR_TSQE_TYPE_IDLE:
conn = le32_to_cpu(tsqe->word_1);
if (SAR_TSQE_TAG(stat) == 0x10) {
#ifdef NOTDEF
printk("%s: Connection %d halted.\n",
card->name,
le32_to_cpu(tsqe->word_1) & 0x1fff);
#endif
break;
}
vc = card->vcs[conn & 0x1fff];
if (!vc) {
printk("%s: could not find VC from conn %d\n",
card->name, conn & 0x1fff);
break;
}
printk("%s: Connection %d IDLE.\n",
card->name, vc->index);
set_bit(VCF_IDLE, &vc->flags);
break;
case SAR_TSQE_TYPE_TSR:
conn = le32_to_cpu(tsqe->word_1);
vc = card->vcs[conn & 0x1fff];
if (!vc) {
printk("%s: no VC at index %d\n",
card->name,
le32_to_cpu(tsqe->word_1) & 0x1fff);
break;
}
drain_scq(card, vc);
break;
case SAR_TSQE_TYPE_TBD_COMP:
conn = le32_to_cpu(tsqe->word_1);
vpi = (conn >> SAR_TBD_VPI_SHIFT) & 0x00ff;
vci = (conn >> SAR_TBD_VCI_SHIFT) & 0xffff;
if (vpi >= (1 << card->vpibits) ||
vci >= (1 << card->vcibits)) {
printk("%s: TBD complete: "
"out of range VPI.VCI %u.%u\n",
card->name, vpi, vci);
break;
}
vc = card->vcs[VPCI2VC(card, vpi, vci)];
if (!vc) {
printk("%s: TBD complete: "
"no VC at VPI.VCI %u.%u\n",
card->name, vpi, vci);
break;
}
drain_scq(card, vc);
break;
}
tsqe->word_2 = cpu_to_le32(SAR_TSQE_INVALID);
card->tsq.next = tsqe;
if (card->tsq.next == card->tsq.last)
tsqe = card->tsq.base;
else
tsqe = card->tsq.next + 1;
TXPRINTK("tsqe: %p: base %p, next %p, last %p\n", tsqe,
card->tsq.base, card->tsq.next, card->tsq.last);
stat = le32_to_cpu(tsqe->word_2);
} while (!(stat & SAR_TSQE_INVALID));
writel((unsigned long)card->tsq.next - (unsigned long)card->tsq.base,
SAR_REG_TSQH);
XPRINTK("idt77252_tx-after writel%d: TSQ head = 0x%x, tail = 0x%x, next = 0x%p.\n",
card->index, readl(SAR_REG_TSQH),
readl(SAR_REG_TSQT), card->tsq.next);
}
static void
tst_timer(unsigned long data)
{
struct idt77252_dev *card = (struct idt77252_dev *)data;
unsigned long base, idle, jump;
unsigned long flags;
u32 pc;
int e;
spin_lock_irqsave(&card->tst_lock, flags);
base = card->tst[card->tst_index];
idle = card->tst[card->tst_index ^ 1];
if (test_bit(TST_SWITCH_WAIT, &card->tst_state)) {
jump = base + card->tst_size - 2;
pc = readl(SAR_REG_NOW) >> 2;
if ((pc ^ idle) & ~(card->tst_size - 1)) {
mod_timer(&card->tst_timer, jiffies + 1);
goto out;
}
clear_bit(TST_SWITCH_WAIT, &card->tst_state);
card->tst_index ^= 1;
write_sram(card, jump, TSTE_OPC_JMP | (base << 2));
base = card->tst[card->tst_index];
idle = card->tst[card->tst_index ^ 1];
for (e = 0; e < card->tst_size - 2; e++) {
if (card->soft_tst[e].tste & TSTE_PUSH_IDLE) {
write_sram(card, idle + e,
card->soft_tst[e].tste & TSTE_MASK);
card->soft_tst[e].tste &= ~(TSTE_PUSH_IDLE);
}
}
}
if (test_and_clear_bit(TST_SWITCH_PENDING, &card->tst_state)) {
for (e = 0; e < card->tst_size - 2; e++) {
if (card->soft_tst[e].tste & TSTE_PUSH_ACTIVE) {
write_sram(card, idle + e,
card->soft_tst[e].tste & TSTE_MASK);
card->soft_tst[e].tste &= ~(TSTE_PUSH_ACTIVE);
card->soft_tst[e].tste |= TSTE_PUSH_IDLE;
}
}
jump = base + card->tst_size - 2;
write_sram(card, jump, TSTE_OPC_NULL);
set_bit(TST_SWITCH_WAIT, &card->tst_state);
mod_timer(&card->tst_timer, jiffies + 1);
}
out:
spin_unlock_irqrestore(&card->tst_lock, flags);
}
static int
__fill_tst(struct idt77252_dev *card, struct vc_map *vc,
int n, unsigned int opc)
{
unsigned long cl, avail;
unsigned long idle;
int e, r;
u32 data;
avail = card->tst_size - 2;
for (e = 0; e < avail; e++) {
if (card->soft_tst[e].vc == NULL)
break;
}
if (e >= avail) {
printk("%s: No free TST entries found\n", card->name);
return -1;
}
NPRINTK("%s: conn %d: first TST entry at %d.\n",
card->name, vc ? vc->index : -1, e);
r = n;
cl = avail;
data = opc & TSTE_OPC_MASK;
if (vc && (opc != TSTE_OPC_NULL))
data = opc | vc->index;
idle = card->tst[card->tst_index ^ 1];
/*
* Fill Soft TST.
*/
while (r > 0) {
if ((cl >= avail) && (card->soft_tst[e].vc == NULL)) {
if (vc)
card->soft_tst[e].vc = vc;
else
card->soft_tst[e].vc = (void *)-1;
card->soft_tst[e].tste = data;
if (timer_pending(&card->tst_timer))
card->soft_tst[e].tste |= TSTE_PUSH_ACTIVE;
else {
write_sram(card, idle + e, data);
card->soft_tst[e].tste |= TSTE_PUSH_IDLE;
}
cl -= card->tst_size;
r--;
}
if (++e == avail)
e = 0;
cl += n;
}
return 0;
}
static int
fill_tst(struct idt77252_dev *card, struct vc_map *vc, int n, unsigned int opc)
{
unsigned long flags;
int res;
spin_lock_irqsave(&card->tst_lock, flags);
res = __fill_tst(card, vc, n, opc);
set_bit(TST_SWITCH_PENDING, &card->tst_state);
if (!timer_pending(&card->tst_timer))
mod_timer(&card->tst_timer, jiffies + 1);
spin_unlock_irqrestore(&card->tst_lock, flags);
return res;
}
static int
__clear_tst(struct idt77252_dev *card, struct vc_map *vc)
{
unsigned long idle;
int e;
idle = card->tst[card->tst_index ^ 1];
for (e = 0; e < card->tst_size - 2; e++) {
if (card->soft_tst[e].vc == vc) {
card->soft_tst[e].vc = NULL;
card->soft_tst[e].tste = TSTE_OPC_VAR;
if (timer_pending(&card->tst_timer))
card->soft_tst[e].tste |= TSTE_PUSH_ACTIVE;
else {
write_sram(card, idle + e, TSTE_OPC_VAR);
card->soft_tst[e].tste |= TSTE_PUSH_IDLE;
}
}
}
return 0;
}
static int
clear_tst(struct idt77252_dev *card, struct vc_map *vc)
{
unsigned long flags;
int res;
spin_lock_irqsave(&card->tst_lock, flags);
res = __clear_tst(card, vc);
set_bit(TST_SWITCH_PENDING, &card->tst_state);
if (!timer_pending(&card->tst_timer))
mod_timer(&card->tst_timer, jiffies + 1);
spin_unlock_irqrestore(&card->tst_lock, flags);
return res;
}
static int
change_tst(struct idt77252_dev *card, struct vc_map *vc,
int n, unsigned int opc)
{
unsigned long flags;
int res;
spin_lock_irqsave(&card->tst_lock, flags);
__clear_tst(card, vc);
res = __fill_tst(card, vc, n, opc);
set_bit(TST_SWITCH_PENDING, &card->tst_state);
if (!timer_pending(&card->tst_timer))
mod_timer(&card->tst_timer, jiffies + 1);
spin_unlock_irqrestore(&card->tst_lock, flags);
return res;
}
static int
set_tct(struct idt77252_dev *card, struct vc_map *vc)
{
unsigned long tct;
tct = (unsigned long) (card->tct_base + vc->index * SAR_SRAM_TCT_SIZE);
switch (vc->class) {
case SCHED_CBR:
OPRINTK("%s: writing TCT at 0x%lx, SCD 0x%lx.\n",
card->name, tct, vc->scq->scd);
write_sram(card, tct + 0, TCT_CBR | vc->scq->scd);
write_sram(card, tct + 1, 0);
write_sram(card, tct + 2, 0);
write_sram(card, tct + 3, 0);
write_sram(card, tct + 4, 0);
write_sram(card, tct + 5, 0);
write_sram(card, tct + 6, 0);
write_sram(card, tct + 7, 0);
break;
case SCHED_UBR:
OPRINTK("%s: writing TCT at 0x%lx, SCD 0x%lx.\n",
card->name, tct, vc->scq->scd);
write_sram(card, tct + 0, TCT_UBR | vc->scq->scd);
write_sram(card, tct + 1, 0);
write_sram(card, tct + 2, TCT_TSIF);
write_sram(card, tct + 3, TCT_HALT | TCT_IDLE);
write_sram(card, tct + 4, 0);
write_sram(card, tct + 5, vc->init_er);
write_sram(card, tct + 6, 0);
write_sram(card, tct + 7, TCT_FLAG_UBR);
break;
case SCHED_VBR:
case SCHED_ABR:
default:
return -ENOSYS;
}
return 0;
}
/*****************************************************************************/
/* */
/* FBQ Handling */
/* */
/*****************************************************************************/
static __inline__ int
idt77252_fbq_level(struct idt77252_dev *card, int queue)
{
return (readl(SAR_REG_STAT) >> (16 + (queue << 2))) & 0x0f;
}
static __inline__ int
idt77252_fbq_full(struct idt77252_dev *card, int queue)
{
return (readl(SAR_REG_STAT) >> (16 + (queue << 2))) == 0x0f;
}
static int
push_rx_skb(struct idt77252_dev *card, struct sk_buff *skb, int queue)
{
unsigned long flags;
u32 handle;
u32 addr;
skb->data = skb->tail = skb->head;
skb->len = 0;
skb_reserve(skb, 16);
switch (queue) {
case 0:
skb_put(skb, SAR_FB_SIZE_0);
break;
case 1:
skb_put(skb, SAR_FB_SIZE_1);
break;
case 2:
skb_put(skb, SAR_FB_SIZE_2);
break;
case 3:
skb_put(skb, SAR_FB_SIZE_3);
break;
default:
dev_kfree_skb(skb);
return -1;
}
if (idt77252_fbq_full(card, queue))
return -1;
memset(&skb->data[(skb->len & ~(0x3f)) - 64], 0, 2 * sizeof(u32));
handle = IDT77252_PRV_POOL(skb);
addr = IDT77252_PRV_PADDR(skb);
spin_lock_irqsave(&card->cmd_lock, flags);
writel(handle, card->fbq[queue]);
writel(addr, card->fbq[queue]);
spin_unlock_irqrestore(&card->cmd_lock, flags);
return 0;
}
static void
add_rx_skb(struct idt77252_dev *card, int queue,
unsigned int size, unsigned int count)
{
struct sk_buff *skb;
dma_addr_t paddr;
u32 handle;
while (count--) {
skb = dev_alloc_skb(size);
if (!skb)
return;
if (sb_pool_add(card, skb, queue)) {
printk("%s: SB POOL full\n", __FUNCTION__);
goto outfree;
}
paddr = pci_map_single(card->pcidev, skb->data,
skb->end - skb->data,
PCI_DMA_FROMDEVICE);
IDT77252_PRV_PADDR(skb) = paddr;
if (push_rx_skb(card, skb, queue)) {
printk("%s: FB QUEUE full\n", __FUNCTION__);
goto outunmap;
}
}
return;
outunmap:
pci_unmap_single(card->pcidev, IDT77252_PRV_PADDR(skb),
skb->end - skb->data, PCI_DMA_FROMDEVICE);
handle = IDT77252_PRV_POOL(skb);
card->sbpool[POOL_QUEUE(handle)].skb[POOL_INDEX(handle)] = NULL;
outfree:
dev_kfree_skb(skb);
}
static void
recycle_rx_skb(struct idt77252_dev *card, struct sk_buff *skb)
{
u32 handle = IDT77252_PRV_POOL(skb);
int err;
err = push_rx_skb(card, skb, POOL_QUEUE(handle));
if (err) {
pci_unmap_single(card->pcidev, IDT77252_PRV_PADDR(skb),
skb->end - skb->data, PCI_DMA_FROMDEVICE);
sb_pool_remove(card, skb);
dev_kfree_skb(skb);
}
}
static void
flush_rx_pool(struct idt77252_dev *card, struct rx_pool *rpp)
{
rpp->len = 0;
rpp->count = 0;
rpp->first = NULL;
rpp->last = &rpp->first;
}
static void
recycle_rx_pool_skb(struct idt77252_dev *card, struct rx_pool *rpp)
{
struct sk_buff *skb, *next;
int i;
skb = rpp->first;
for (i = 0; i < rpp->count; i++) {
next = IDT77252_PRV_NEXT(skb);
recycle_rx_skb(card, skb);
skb = next;
}
flush_rx_pool(card, rpp);
}
/*****************************************************************************/
/* */
/* ATM Interface */
/* */
/*****************************************************************************/
static void
idt77252_phy_put(struct atm_dev *dev, unsigned char value, unsigned long addr)
{
write_utility(dev->dev_data, 0x100 + (addr & 0x1ff), value);
}
static unsigned char
idt77252_phy_get(struct atm_dev *dev, unsigned long addr)
{
return read_utility(dev->dev_data, 0x100 + (addr & 0x1ff));
}
static int
idt77252_send_skb(struct atm_vcc *vcc, struct sk_buff *skb, int oam)
{
struct atm_dev *dev = vcc->dev;
struct idt77252_dev *card = dev->dev_data;
struct vc_map *vc = vcc->dev_data;
int err;
if (vc == NULL) {
printk("%s: NULL connection in send().\n", card->name);
atomic_inc(&vcc->stats->tx_err);
dev_kfree_skb(skb);
return -EINVAL;
}
if (!test_bit(VCF_TX, &vc->flags)) {
printk("%s: Trying to transmit on a non-tx VC.\n", card->name);
atomic_inc(&vcc->stats->tx_err);
dev_kfree_skb(skb);
return -EINVAL;
}
switch (vcc->qos.aal) {
case ATM_AAL0:
case ATM_AAL1:
case ATM_AAL5:
break;
default:
printk("%s: Unsupported AAL: %d\n", card->name, vcc->qos.aal);
atomic_inc(&vcc->stats->tx_err);
dev_kfree_skb(skb);
return -EINVAL;
}
if (ATM_SKB(skb)->iovcnt != 0) {
printk("%s: No scatter-gather yet.\n", card->name);
atomic_inc(&vcc->stats->tx_err);
dev_kfree_skb(skb);
return -EINVAL;
}
ATM_SKB(skb)->vcc = vcc;
err = queue_skb(card, vc, skb, oam);
if (err) {
atomic_inc(&vcc->stats->tx_err);
dev_kfree_skb(skb);
return err;
}
return 0;
}
int
idt77252_send(struct atm_vcc *vcc, struct sk_buff *skb)
{
return idt77252_send_skb(vcc, skb, 0);
}
static int
idt77252_send_oam(struct atm_vcc *vcc, void *cell, int flags)
{
struct atm_dev *dev = vcc->dev;
struct idt77252_dev *card = dev->dev_data;
struct sk_buff *skb;
skb = dev_alloc_skb(64);
if (!skb) {
printk("%s: Out of memory in send_oam().\n", card->name);
atomic_inc(&vcc->stats->tx_err);
return -ENOMEM;
}
atomic_add(skb->truesize + ATM_PDU_OVHD, &vcc->tx_inuse);
ATM_SKB(skb)->iovcnt = 0;
memcpy(skb_put(skb, 52), cell, 52);
return idt77252_send_skb(vcc, skb, 1);
}
static __inline__ unsigned int
idt77252_fls(unsigned int x)
{
int r = 1;
if (x == 0)
return 0;
if (x & 0xffff0000) {
x >>= 16;
r += 16;
}
if (x & 0xff00) {
x >>= 8;
r += 8;
}
if (x & 0xf0) {
x >>= 4;
r += 4;
}
if (x & 0xc) {
x >>= 2;
r += 2;
}
if (x & 0x2)
r += 1;
return r;
}
static u16
idt77252_int_to_atmfp(unsigned int rate)
{
u16 m, e;
if (rate == 0)
return 0;
e = idt77252_fls(rate) - 1;
if (e < 9)
m = (rate - (1 << e)) << (9 - e);
else if (e == 9)
m = (rate - (1 << e));
else /* e > 9 */
m = (rate - (1 << e)) >> (e - 9);
return 0x4000 | (e << 9) | m;
}
static u8
idt77252_rate_logindex(struct idt77252_dev *card, int pcr)
{
u16 afp;
afp = idt77252_int_to_atmfp(pcr < 0 ? -pcr : pcr);
if (pcr < 0)
return rate_to_log[(afp >> 5) & 0x1ff];
return rate_to_log[((afp >> 5) + 1) & 0x1ff];
}
static void
idt77252_est_timer(unsigned long data)
{
struct vc_map *vc = (struct vc_map *)data;
struct idt77252_dev *card = vc->card;
struct rate_estimator *est;
unsigned long flags;
u32 rate, cps;
u64 ncells;
u8 lacr;
spin_lock_irqsave(&vc->lock, flags);
est = vc->estimator;
if (!est)
goto out;
ncells = est->cells;
rate = ((u32)(ncells - est->last_cells)) << (7 - est->interval);
est->last_cells = ncells;
est->avcps += ((long)rate - (long)est->avcps) >> est->ewma_log;
est->cps = (est->avcps + 0x1f) >> 5;
cps = est->cps;
if (cps < (est->maxcps >> 4))
cps = est->maxcps >> 4;
lacr = idt77252_rate_logindex(card, cps);
if (lacr > vc->max_er)
lacr = vc->max_er;
if (lacr != vc->lacr) {
vc->lacr = lacr;
writel(TCMDQ_LACR|(vc->lacr << 16)|vc->index, SAR_REG_TCMDQ);
}
est->timer.expires = jiffies + ((HZ / 4) << est->interval);
add_timer(&est->timer);
out:
spin_unlock_irqrestore(&vc->lock, flags);
}
static struct rate_estimator *
idt77252_init_est(struct vc_map *vc, int pcr)
{
struct rate_estimator *est;
est = kmalloc(sizeof(struct rate_estimator), GFP_KERNEL);
if (!est)
return NULL;
memset(est, 0, sizeof(*est));
est->maxcps = pcr < 0 ? -pcr : pcr;
est->cps = est->maxcps;
est->avcps = est->cps << 5;
est->interval = 2; /* XXX: make this configurable */
est->ewma_log = 2; /* XXX: make this configurable */
est->timer.data = (unsigned long)vc;
est->timer.function = idt77252_est_timer;
init_timer(&est->timer);
est->timer.expires = jiffies + ((HZ / 4) << est->interval);
add_timer(&est->timer);
return est;
}
static int
idt77252_init_cbr(struct idt77252_dev *card, struct vc_map *vc,
struct atm_vcc *vcc, struct atm_qos *qos)
{
int tst_free, tst_used, tst_entries;
unsigned long tmpl, modl;
int tcr, tcra;
if ((qos->txtp.max_pcr == 0) &&
(qos->txtp.pcr == 0) && (qos->txtp.min_pcr == 0)) {
printk("%s: trying to open a CBR VC with cell rate = 0\n",
card->name);
return -EINVAL;
}
tst_used = 0;
tst_free = card->tst_free;
if (test_bit(VCF_TX, &vc->flags))
tst_used = vc->ntste;
tst_free += tst_used;
tcr = atm_pcr_goal(&qos->txtp);
tcra = tcr >= 0 ? tcr : -tcr;
TXPRINTK("%s: CBR target cell rate = %d\n", card->name, tcra);
tmpl = (unsigned long) tcra * ((unsigned long) card->tst_size - 2);
modl = tmpl % (unsigned long)card->utopia_pcr;
tst_entries = (int) (tmpl / card->utopia_pcr);
if (tcr > 0) {
if (modl > 0)
tst_entries++;
} else if (tcr == 0) {
tst_entries = tst_free - SAR_TST_RESERVED;
if (tst_entries <= 0) {
printk("%s: no CBR bandwidth free.\n", card->name);
return -ENOSR;
}
}
if (tst_entries == 0) {
printk("%s: selected CBR bandwidth < granularity.\n",
card->name);
return -EINVAL;
}
if (tst_entries > (tst_free - SAR_TST_RESERVED)) {
printk("%s: not enough CBR bandwidth free.\n", card->name);
return -ENOSR;
}
vc->ntste = tst_entries;
card->tst_free = tst_free - tst_entries;
if (test_bit(VCF_TX, &vc->flags)) {
if (tst_used == tst_entries)
return 0;
OPRINTK("%s: modify %d -> %d entries in TST.\n",
card->name, tst_used, tst_entries);
change_tst(card, vc, tst_entries, TSTE_OPC_CBR);
return 0;
}
OPRINTK("%s: setting %d entries in TST.\n", card->name, tst_entries);
fill_tst(card, vc, tst_entries, TSTE_OPC_CBR);
return 0;
}
static int
idt77252_init_ubr(struct idt77252_dev *card, struct vc_map *vc,
struct atm_vcc *vcc, struct atm_qos *qos)
{
unsigned long flags;
int tcr;
spin_lock_irqsave(&vc->lock, flags);
if (vc->estimator) {
del_timer(&vc->estimator->timer);
kfree(vc->estimator);
vc->estimator = NULL;
}
spin_unlock_irqrestore(&vc->lock, flags);
tcr = atm_pcr_goal(&qos->txtp);
if (tcr == 0)
tcr = card->link_pcr;
vc->estimator = idt77252_init_est(vc, tcr);
vc->class = SCHED_UBR;
vc->init_er = idt77252_rate_logindex(card, tcr);
vc->lacr = vc->init_er;
if (tcr < 0)
vc->max_er = vc->init_er;
else
vc->max_er = 0xff;
return 0;
}
static int
idt77252_init_tx(struct idt77252_dev *card, struct vc_map *vc,
struct atm_vcc *vcc, struct atm_qos *qos)
{
int error;
if (test_bit(VCF_TX, &vc->flags))
return -EBUSY;
switch (qos->txtp.traffic_class) {
case ATM_CBR:
vc->class = SCHED_CBR;
break;
case ATM_UBR:
vc->class = SCHED_UBR;
break;
case ATM_VBR:
case ATM_ABR:
default:
return -EPROTONOSUPPORT;
}
vc->scq = alloc_scq(card, vc->class);
if (!vc->scq) {
printk("%s: can't get SCQ.\n", card->name);
return -ENOMEM;
}
vc->scq->scd = get_free_scd(card, vc);
if (vc->scq->scd == 0) {
printk("%s: no SCD available.\n", card->name);
free_scq(card, vc->scq);
return -ENOMEM;
}
fill_scd(card, vc->scq, vc->class);
if (set_tct(card, vc)) {
printk("%s: class %d not supported.\n",
card->name, qos->txtp.traffic_class);
card->scd2vc[vc->scd_index] = NULL;
free_scq(card, vc->scq);
return -EPROTONOSUPPORT;
}
switch (vc->class) {
case SCHED_CBR:
error = idt77252_init_cbr(card, vc, vcc, qos);
if (error) {
card->scd2vc[vc->scd_index] = NULL;
free_scq(card, vc->scq);
return error;
}
clear_bit(VCF_IDLE, &vc->flags);
writel(TCMDQ_START | vc->index, SAR_REG_TCMDQ);
break;
case SCHED_UBR:
error = idt77252_init_ubr(card, vc, vcc, qos);
if (error) {
card->scd2vc[vc->scd_index] = NULL;
free_scq(card, vc->scq);
return error;
}
set_bit(VCF_IDLE, &vc->flags);
break;
}
vc->tx_vcc = vcc;
set_bit(VCF_TX, &vc->flags);
return 0;
}
static int
idt77252_init_rx(struct idt77252_dev *card, struct vc_map *vc,
struct atm_vcc *vcc, struct atm_qos *qos)
{
unsigned long flags;
unsigned long addr;
u32 rcte = 0;
if (test_bit(VCF_RX, &vc->flags))
return -EBUSY;
vc->rx_vcc = vcc;
set_bit(VCF_RX, &vc->flags);
if ((vcc->vci == 3) || (vcc->vci == 4))
return 0;
flush_rx_pool(card, &vc->rcv.rx_pool);
rcte |= SAR_RCTE_CONNECTOPEN;
rcte |= SAR_RCTE_RAWCELLINTEN;
switch (qos->aal) {
case ATM_AAL0:
rcte |= SAR_RCTE_RCQ;
break;
case ATM_AAL1:
rcte |= SAR_RCTE_OAM; /* Let SAR drop Video */
break;
case ATM_AAL34:
rcte |= SAR_RCTE_AAL34;
break;
case ATM_AAL5:
rcte |= SAR_RCTE_AAL5;
break;
default:
rcte |= SAR_RCTE_RCQ;
break;
}
if (qos->aal != ATM_AAL5)
rcte |= SAR_RCTE_FBP_1;
else if (qos->rxtp.max_sdu > SAR_FB_SIZE_2)
rcte |= SAR_RCTE_FBP_3;
else if (qos->rxtp.max_sdu > SAR_FB_SIZE_1)
rcte |= SAR_RCTE_FBP_2;
else if (qos->rxtp.max_sdu > SAR_FB_SIZE_0)
rcte |= SAR_RCTE_FBP_1;
else
rcte |= SAR_RCTE_FBP_01;
addr = card->rct_base + (vc->index << 2);
OPRINTK("%s: writing RCT at 0x%lx\n", card->name, addr);
write_sram(card, addr, rcte);
spin_lock_irqsave(&card->cmd_lock, flags);
writel(SAR_CMD_OPEN_CONNECTION | (addr << 2), SAR_REG_CMD);
waitfor_idle(card);
spin_unlock_irqrestore(&card->cmd_lock, flags);
return 0;
}
static int
idt77252_find_vcc(struct atm_vcc *vcc, short *vpi, int *vci)
{
struct atm_vcc *walk;
if (*vpi == ATM_VPI_ANY) {
*vpi = 0;
walk = vcc->dev->vccs;
while (walk) {
if ((walk->vci == *vci) && (walk->vpi == *vpi)) {
(*vpi)++;
walk = vcc->dev->vccs;
continue;
}
walk = walk->next;
}
}
if (*vci == ATM_VCI_ANY) {
*vci = ATM_NOT_RSV_VCI;
walk = vcc->dev->vccs;
while (walk) {
if ((walk->vci == *vci) && (walk->vpi == *vpi)) {
(*vci)++;
walk = vcc->dev->vccs;
continue;
}
walk = walk->next;
}
}
return 0;
}
static int
idt77252_open(struct atm_vcc *vcc, short vpi, int vci)
{
struct atm_dev *dev = vcc->dev;
struct idt77252_dev *card = dev->dev_data;
struct vc_map *vc;
unsigned int index;
unsigned int inuse;
int error;
idt77252_find_vcc(vcc, &vpi, &vci);
if (vpi == ATM_VPI_UNSPEC || vci == ATM_VCI_UNSPEC)
return 0;
if (vpi >= (1 << card->vpibits)) {
printk("%s: unsupported VPI: %d\n", card->name, vpi);
return -EINVAL;
}
if (vci >= (1 << card->vcibits)) {
printk("%s: unsupported VCI: %d\n", card->name, vci);
return -EINVAL;
}
vcc->vpi = vpi;
vcc->vci = vci;
set_bit(ATM_VF_ADDR, &vcc->flags);
down(&card->mutex);
OPRINTK("%s: opening vpi.vci: %d.%d\n", card->name, vpi, vci);
switch (vcc->qos.aal) {
case ATM_AAL0:
case ATM_AAL1:
case ATM_AAL5:
break;
default:
printk("%s: Unsupported AAL: %d\n", card->name, vcc->qos.aal);
up(&card->mutex);
return -EPROTONOSUPPORT;
}
index = VPCI2VC(card, vpi, vci);
if (!card->vcs[index]) {
card->vcs[index] = kmalloc(sizeof(struct vc_map), GFP_KERNEL);
if (!card->vcs[index]) {
printk("%s: can't alloc vc in open()\n", card->name);
up(&card->mutex);
return -ENOMEM;
}
memset(card->vcs[index], 0, sizeof(struct vc_map));
card->vcs[index]->card = card;
card->vcs[index]->index = index;
spin_lock_init(&card->vcs[index]->lock);
}
vc = card->vcs[index];
vcc->dev_data = vc;
IPRINTK("%s: idt77252_open: vc = %d (%d.%d) %s/%s (max RX SDU: %u)\n",
card->name, vc->index, vcc->vpi, vcc->vci,
vcc->qos.rxtp.traffic_class != ATM_NONE ? "rx" : "--",
vcc->qos.txtp.traffic_class != ATM_NONE ? "tx" : "--",
vcc->qos.rxtp.max_sdu);
inuse = 0;
if (vcc->qos.txtp.traffic_class != ATM_NONE &&
test_bit(VCF_TX, &vc->flags))
inuse = 1;
if (vcc->qos.rxtp.traffic_class != ATM_NONE &&
test_bit(VCF_RX, &vc->flags))
inuse += 2;
if (inuse) {
printk("%s: %s vci already in use.\n", card->name,
inuse == 1 ? "tx" : inuse == 2 ? "rx" : "tx and rx");
up(&card->mutex);
return -EADDRINUSE;
}
if (vcc->qos.txtp.traffic_class != ATM_NONE) {
error = idt77252_init_tx(card, vc, vcc, &vcc->qos);
if (error) {
up(&card->mutex);
return error;
}
}
if (vcc->qos.rxtp.traffic_class != ATM_NONE) {
error = idt77252_init_rx(card, vc, vcc, &vcc->qos);
if (error) {
up(&card->mutex);
return error;
}
}
set_bit(ATM_VF_READY, &vcc->flags);
MOD_INC_USE_COUNT;
up(&card->mutex);
return 0;
}
static void
idt77252_close(struct atm_vcc *vcc)
{
struct atm_dev *dev = vcc->dev;
struct idt77252_dev *card = dev->dev_data;
struct vc_map *vc = vcc->dev_data;
unsigned long flags;
unsigned long addr;
int timeout;
down(&card->mutex);
IPRINTK("%s: idt77252_close: vc = %d (%d.%d)\n",
card->name, vc->index, vcc->vpi, vcc->vci);
clear_bit(ATM_VF_READY, &vcc->flags);
if (vcc->qos.rxtp.traffic_class != ATM_NONE) {
spin_lock_irqsave(&vc->lock, flags);
clear_bit(VCF_RX, &vc->flags);
vc->rx_vcc = NULL;
spin_unlock_irqrestore(&vc->lock, flags);
if ((vcc->vci == 3) || (vcc->vci == 4))
goto done;
addr = card->rct_base + vc->index * SAR_SRAM_RCT_SIZE;
spin_lock_irqsave(&card->cmd_lock, flags);
writel(SAR_CMD_CLOSE_CONNECTION | (addr << 2), SAR_REG_CMD);
waitfor_idle(card);
spin_unlock_irqrestore(&card->cmd_lock, flags);
if (vc->rcv.rx_pool.count) {
DPRINTK("%s: closing a VC with pending rx buffers.\n",
card->name);
recycle_rx_pool_skb(card, &vc->rcv.rx_pool);
}
}
done:
if (vcc->qos.txtp.traffic_class != ATM_NONE) {
spin_lock_irqsave(&vc->lock, flags);
clear_bit(VCF_TX, &vc->flags);
clear_bit(VCF_IDLE, &vc->flags);
clear_bit(VCF_RSV, &vc->flags);
vc->tx_vcc = NULL;
if (vc->estimator) {
del_timer(&vc->estimator->timer);
kfree(vc->estimator);
vc->estimator = NULL;
}
spin_unlock_irqrestore(&vc->lock, flags);
timeout = 5 * HZ;
while (atomic_read(&vc->scq->used) > 0) {
timeout = schedule_timeout(timeout);
if (!timeout)
break;
}
if (!timeout)
printk("%s: SCQ drain timeout: %u used\n",
card->name, atomic_read(&vc->scq->used));
writel(TCMDQ_HALT | vc->index, SAR_REG_TCMDQ);
clear_scd(card, vc->scq, vc->class);
if (vc->class == SCHED_CBR) {
clear_tst(card, vc);
card->tst_free += vc->ntste;
vc->ntste = 0;
}
card->scd2vc[vc->scd_index] = NULL;
free_scq(card, vc->scq);
}
MOD_DEC_USE_COUNT;
up(&card->mutex);
}
static int
idt77252_change_qos(struct atm_vcc *vcc, struct atm_qos *qos, int flags)
{
struct atm_dev *dev = vcc->dev;
struct idt77252_dev *card = dev->dev_data;
struct vc_map *vc = vcc->dev_data;
int error = 0;
down(&card->mutex);
if (qos->txtp.traffic_class != ATM_NONE) {
if (!test_bit(VCF_TX, &vc->flags)) {
error = idt77252_init_tx(card, vc, vcc, qos);
if (error)
goto out;
} else {
switch (qos->txtp.traffic_class) {
case ATM_CBR:
error = idt77252_init_cbr(card, vc, vcc, qos);
if (error)
goto out;
break;
case ATM_UBR:
error = idt77252_init_ubr(card, vc, vcc, qos);
if (error)
goto out;
if (!test_bit(VCF_IDLE, &vc->flags)) {
writel(TCMDQ_LACR | (vc->lacr << 16) |
vc->index, SAR_REG_TCMDQ);
}
break;
case ATM_VBR:
case ATM_ABR:
error = -EOPNOTSUPP;
goto out;
}
}
}
if ((qos->rxtp.traffic_class != ATM_NONE) &&
!test_bit(VCF_RX, &vc->flags)) {
error = idt77252_init_rx(card, vc, vcc, qos);
if (error)
goto out;
}
memcpy(&vcc->qos, qos, sizeof(struct atm_qos));
set_bit(ATM_VF_HASQOS, &vcc->flags);
out:
up(&card->mutex);
return error;
}
static int
idt77252_proc_read(struct atm_dev *dev, loff_t * pos, char *page)
{
struct idt77252_dev *card = dev->dev_data;
int i, left;
left = (int) *pos;
if (!left--)
return sprintf(page, "IDT77252 Interrupts:\n");
if (!left--)
return sprintf(page, "TSIF: %u\n", card->irqstat[15]);
if (!left--)
return sprintf(page, "TXICP: %u\n", card->irqstat[14]);
if (!left--)
return sprintf(page, "TSQF: %u\n", card->irqstat[12]);
if (!left--)
return sprintf(page, "TMROF: %u\n", card->irqstat[11]);
if (!left--)
return sprintf(page, "PHYI: %u\n", card->irqstat[10]);
if (!left--)
return sprintf(page, "FBQ3A: %u\n", card->irqstat[8]);
if (!left--)
return sprintf(page, "FBQ2A: %u\n", card->irqstat[7]);
if (!left--)
return sprintf(page, "RSQF: %u\n", card->irqstat[6]);
if (!left--)
return sprintf(page, "EPDU: %u\n", card->irqstat[5]);
if (!left--)
return sprintf(page, "RAWCF: %u\n", card->irqstat[4]);
if (!left--)
return sprintf(page, "FBQ1A: %u\n", card->irqstat[3]);
if (!left--)
return sprintf(page, "FBQ0A: %u\n", card->irqstat[2]);
if (!left--)
return sprintf(page, "RSQAF: %u\n", card->irqstat[1]);
if (!left--)
return sprintf(page, "IDT77252 Transmit Connection Table:\n");
for (i = 0; i < card->tct_size; i++) {
unsigned long tct;
struct atm_vcc *vcc;
struct vc_map *vc;
char *p;
vc = card->vcs[i];
if (!vc)
continue;
vcc = NULL;
if (vc->tx_vcc)
vcc = vc->tx_vcc;
if (!vcc)
continue;
if (left--)
continue;
p = page;
p += sprintf(p, " %4u: %u.%u: ", i, vcc->vpi, vcc->vci);
tct = (unsigned long) (card->tct_base + i * SAR_SRAM_TCT_SIZE);
for (i = 0; i < 8; i++)
p += sprintf(p, " %08x", read_sram(card, tct + i));
p += sprintf(p, "\n");
return p - page;
}
return 0;
}
/*****************************************************************************/
/* */
/* Interrupt handler */
/* */
/*****************************************************************************/
static void
idt77252_collect_stat(struct idt77252_dev *card)
{
u32 cdc, vpec, icc;
cdc = readl(SAR_REG_CDC);
vpec = readl(SAR_REG_VPEC);
icc = readl(SAR_REG_ICC);
#ifdef NOTDEF
printk("%s:", card->name);
if (cdc & 0x7f0000) {
char *s = "";
printk(" [");
if (cdc & (1 << 22)) {
printk("%sRM ID", s);
s = " | ";
}
if (cdc & (1 << 21)) {
printk("%sCON TAB", s);
s = " | ";
}
if (cdc & (1 << 20)) {
printk("%sNO FB", s);
s = " | ";
}
if (cdc & (1 << 19)) {
printk("%sOAM CRC", s);
s = " | ";
}
if (cdc & (1 << 18)) {
printk("%sRM CRC", s);
s = " | ";
}
if (cdc & (1 << 17)) {
printk("%sRM FIFO", s);
s = " | ";
}
if (cdc & (1 << 16)) {
printk("%sRX FIFO", s);
s = " | ";
}
printk("]");
}
printk(" CDC %04x, VPEC %04x, ICC: %04x\n",
cdc & 0xffff, vpec & 0xffff, icc & 0xffff);
#endif
}
static void
idt77252_interrupt(int irq, void *dev_id, struct pt_regs *ptregs)
{
struct idt77252_dev *card = dev_id;
u32 stat;
stat = readl(SAR_REG_STAT) & 0xffff;
if (!stat) /* no interrupt for us */
return;
if (test_and_set_bit(IDT77252_BIT_INTERRUPT, &card->flags)) {
printk("%s: Re-entering irq_handler()\n", card->name);
goto out;
}
writel(stat, SAR_REG_STAT); /* reset interrupt */
if (stat & SAR_STAT_TSIF) { /* entry written to TSQ */
INTPRINTK("%s: TSIF\n", card->name);
card->irqstat[15]++;
idt77252_tx(card);
}
if (stat & SAR_STAT_TXICP) { /* Incomplete CS-PDU has */
INTPRINTK("%s: TXICP\n", card->name);
card->irqstat[14]++;
#ifdef DEBUG
idt77252_tx_dump(card);
#endif
}
if (stat & SAR_STAT_TSQF) { /* TSQ 7/8 full */
INTPRINTK("%s: TSQF\n", card->name);
card->irqstat[12]++;
idt77252_tx(card);
}
if (stat & SAR_STAT_TMROF) { /* Timer overflow */
INTPRINTK("%s: TMROF\n", card->name);
card->irqstat[11]++;
idt77252_collect_stat(card);
}
if (stat & SAR_STAT_EPDU) { /* Got complete CS-PDU */
INTPRINTK("%s: EPDU\n", card->name);
card->irqstat[5]++;
idt77252_rx(card);
}
if (stat & SAR_STAT_RSQAF) { /* RSQ is 7/8 full */
INTPRINTK("%s: RSQAF\n", card->name);
card->irqstat[1]++;
idt77252_rx(card);
}
if (stat & SAR_STAT_RSQF) { /* RSQ is full */
INTPRINTK("%s: RSQF\n", card->name);
card->irqstat[6]++;
idt77252_rx(card);
}
if (stat & SAR_STAT_RAWCF) { /* Raw cell received */
INTPRINTK("%s: RAWCF\n", card->name);
card->irqstat[4]++;
idt77252_rx_raw(card);
}
if (stat & SAR_STAT_PHYI) { /* PHY device interrupt */
INTPRINTK("%s: PHYI", card->name);
card->irqstat[10]++;
if (card->atmdev->phy && card->atmdev->phy->interrupt)
card->atmdev->phy->interrupt(card->atmdev);
}
if (stat & (SAR_STAT_FBQ0A | SAR_STAT_FBQ1A |
SAR_STAT_FBQ2A | SAR_STAT_FBQ3A)) {
writel(readl(SAR_REG_CFG) & ~(SAR_CFG_FBIE), SAR_REG_CFG);
INTPRINTK("%s: FBQA: %04x\n", card->name, stat);
if (stat & SAR_STAT_FBQ0A)
card->irqstat[2]++;
if (stat & SAR_STAT_FBQ1A)
card->irqstat[3]++;
if (stat & SAR_STAT_FBQ2A)
card->irqstat[7]++;
if (stat & SAR_STAT_FBQ3A)
card->irqstat[8]++;
queue_task(&card->tqueue, &tq_immediate);
mark_bh(IMMEDIATE_BH);
}
out:
clear_bit(IDT77252_BIT_INTERRUPT, &card->flags);
}
static void
idt77252_softint(void *dev_id)
{
struct idt77252_dev *card = dev_id;
u32 stat;
int done;
for (done = 1; ; done = 1) {
stat = readl(SAR_REG_STAT) >> 16;
if ((stat & 0x0f) < SAR_FBQ0_HIGH) {
add_rx_skb(card, 0, SAR_FB_SIZE_0, 32);
done = 0;
}
stat >>= 4;
if ((stat & 0x0f) < SAR_FBQ1_HIGH) {
add_rx_skb(card, 1, SAR_FB_SIZE_1, 32);
done = 0;
}
stat >>= 4;
if ((stat & 0x0f) < SAR_FBQ2_HIGH) {
add_rx_skb(card, 2, SAR_FB_SIZE_2, 32);
done = 0;
}
stat >>= 4;
if ((stat & 0x0f) < SAR_FBQ3_HIGH) {
add_rx_skb(card, 3, SAR_FB_SIZE_3, 32);
done = 0;
}
if (done)
break;
}
writel(readl(SAR_REG_CFG) | SAR_CFG_FBIE, SAR_REG_CFG);
}
static int
open_card_oam(struct idt77252_dev *card)
{
unsigned long flags;
unsigned long addr;
struct vc_map *vc;
int vpi, vci;
int index;
u32 rcte;
for (vpi = 0; vpi < (1 << card->vpibits); vpi++) {
for (vci = 3; vci < 5; vci++) {
index = VPCI2VC(card, vpi, vci);
vc = kmalloc(sizeof(struct vc_map), GFP_KERNEL);
if (!vc) {
printk("%s: can't alloc vc\n", card->name);
return -ENOMEM;
}
memset(vc, 0, sizeof(struct vc_map));
vc->index = index;
card->vcs[index] = vc;
flush_rx_pool(card, &vc->rcv.rx_pool);
rcte = SAR_RCTE_CONNECTOPEN |
SAR_RCTE_RAWCELLINTEN |
SAR_RCTE_RCQ |
SAR_RCTE_FBP_1;
addr = card->rct_base + (vc->index << 2);
write_sram(card, addr, rcte);
spin_lock_irqsave(&card->cmd_lock, flags);
writel(SAR_CMD_OPEN_CONNECTION | (addr << 2),
SAR_REG_CMD);
waitfor_idle(card);
spin_unlock_irqrestore(&card->cmd_lock, flags);
}
}
return 0;
}
static void
close_card_oam(struct idt77252_dev *card)
{
unsigned long flags;
unsigned long addr;
struct vc_map *vc;
int vpi, vci;
int index;
for (vpi = 0; vpi < (1 << card->vpibits); vpi++) {
for (vci = 3; vci < 5; vci++) {
index = VPCI2VC(card, vpi, vci);
vc = card->vcs[index];
addr = card->rct_base + vc->index * SAR_SRAM_RCT_SIZE;
spin_lock_irqsave(&card->cmd_lock, flags);
writel(SAR_CMD_CLOSE_CONNECTION | (addr << 2),
SAR_REG_CMD);
waitfor_idle(card);
spin_unlock_irqrestore(&card->cmd_lock, flags);
if (vc->rcv.rx_pool.count) {
DPRINTK("%s: closing a VC "
"with pending rx buffers.\n",
card->name);
recycle_rx_pool_skb(card, &vc->rcv.rx_pool);
}
}
}
}
static int
open_card_ubr0(struct idt77252_dev *card)
{
struct vc_map *vc;
vc = kmalloc(sizeof(struct vc_map), GFP_KERNEL);
if (!vc) {
printk("%s: can't alloc vc\n", card->name);
return -ENOMEM;
}
memset(vc, 0, sizeof(struct vc_map));
card->vcs[0] = vc;
vc->class = SCHED_UBR0;
vc->scq = alloc_scq(card, vc->class);
if (!vc->scq) {
printk("%s: can't get SCQ.\n", card->name);
return -ENOMEM;
}
card->scd2vc[0] = vc;
vc->scd_index = 0;
vc->scq->scd = card->scd_base;
fill_scd(card, vc->scq, vc->class);
write_sram(card, card->tct_base + 0, TCT_UBR | card->scd_base);
write_sram(card, card->tct_base + 1, 0);
write_sram(card, card->tct_base + 2, 0);
write_sram(card, card->tct_base + 3, 0);
write_sram(card, card->tct_base + 4, 0);
write_sram(card, card->tct_base + 5, 0);
write_sram(card, card->tct_base + 6, 0);
write_sram(card, card->tct_base + 7, TCT_FLAG_UBR);
clear_bit(VCF_IDLE, &vc->flags);
writel(TCMDQ_START | 0, SAR_REG_TCMDQ);
return 0;
}
static int
idt77252_dev_open(struct idt77252_dev *card)
{
u32 conf;
if (!test_bit(IDT77252_BIT_INIT, &card->flags)) {
printk("%s: SAR not yet initialized.\n", card->name);
return -1;
}
conf = SAR_CFG_RXPTH| /* enable receive path */
SAR_RX_DELAY | /* interrupt on complete PDU */
SAR_CFG_RAWIE | /* interrupt enable on raw cells */
SAR_CFG_RQFIE | /* interrupt on RSQ almost full */
SAR_CFG_TMOIE | /* interrupt on timer overflow */
SAR_CFG_FBIE | /* interrupt on low free buffers */
SAR_CFG_TXEN | /* transmit operation enable */
SAR_CFG_TXINT | /* interrupt on transmit status */
SAR_CFG_TXUIE | /* interrupt on transmit underrun */
SAR_CFG_TXSFI | /* interrupt on TSQ almost full */
SAR_CFG_PHYIE /* enable PHY interrupts */
;
#ifdef CONFIG_ATM_IDT77252_RCV_ALL
/* Test RAW cell receive. */
conf |= SAR_CFG_VPECA;
#endif
writel(readl(SAR_REG_CFG) | conf, SAR_REG_CFG);
if (open_card_oam(card)) {
printk("%s: Error initializing OAM.\n", card->name);
return -1;
}
if (open_card_ubr0(card)) {
printk("%s: Error initializing UBR0.\n", card->name);
return -1;
}
IPRINTK("%s: opened IDT77252 ABR SAR.\n", card->name);
return 0;
}
void
idt77252_dev_close(struct atm_dev *dev)
{
struct idt77252_dev *card = dev->dev_data;
u32 conf;
close_card_oam(card);
conf = SAR_CFG_RXPTH | /* enable receive path */
SAR_RX_DELAY | /* interrupt on complete PDU */
SAR_CFG_RAWIE | /* interrupt enable on raw cells */
SAR_CFG_RQFIE | /* interrupt on RSQ almost full */
SAR_CFG_TMOIE | /* interrupt on timer overflow */
SAR_CFG_FBIE | /* interrupt on low free buffers */
SAR_CFG_TXEN | /* transmit operation enable */
SAR_CFG_TXINT | /* interrupt on transmit status */
SAR_CFG_TXUIE | /* interrupt on xmit underrun */
SAR_CFG_TXSFI /* interrupt on TSQ almost full */
;
writel(readl(SAR_REG_CFG) & ~(conf), SAR_REG_CFG);
DIPRINTK("%s: closed IDT77252 ABR SAR.\n", card->name);
}
/*****************************************************************************/
/* */
/* Initialisation and Deinitialization of IDT77252 */
/* */
/*****************************************************************************/
static void
deinit_card(struct idt77252_dev *card)
{
struct sk_buff *skb;
int i, j;
if (!test_bit(IDT77252_BIT_INIT, &card->flags)) {
printk("%s: SAR not yet initialized.\n", card->name);
return;
}
DIPRINTK("idt77252: deinitialize card %u\n", card->index);
writel(0, SAR_REG_CFG);
if (card->atmdev)
atm_dev_deregister(card->atmdev);
for (i = 0; i < 4; i++) {
for (j = 0; j < FBQ_SIZE; j++) {
skb = card->sbpool[i].skb[j];
if (skb) {
pci_unmap_single(card->pcidev,
IDT77252_PRV_PADDR(skb),
skb->end - skb->data,
PCI_DMA_FROMDEVICE);
card->sbpool[i].skb[j] = NULL;
dev_kfree_skb(skb);
}
}
}
if (card->soft_tst)
vfree(card->soft_tst);
if (card->scd2vc)
vfree(card->scd2vc);
if (card->vcs)
vfree(card->vcs);
if (card->raw_cell_hnd) {
pci_free_consistent(card->pcidev, 2 * sizeof(u32),
card->raw_cell_hnd, card->raw_cell_paddr);
}
if (card->rsq.base) {
DIPRINTK("%s: Release RSQ ...\n", card->name);
deinit_rsq(card);
}
if (card->tsq.base) {
DIPRINTK("%s: Release TSQ ...\n", card->name);
deinit_tsq(card);
}
DIPRINTK("idt77252: Release IRQ.\n");
free_irq(card->pcidev->irq, card);
for (i = 0; i < 4; i++) {
if (card->fbq[i])
iounmap((void *) card->fbq[i]);
}
if (card->membase)
iounmap((void *) card->membase);
clear_bit(IDT77252_BIT_INIT, &card->flags);
DIPRINTK("%s: Card deinitialized.\n", card->name);
}
static int
init_sram(struct idt77252_dev *card)
{
int i;
for (i = 0; i < card->sramsize; i += 4)
write_sram(card, (i >> 2), 0);
/* set SRAM layout for THIS card */
if (card->sramsize == (512 * 1024)) {
card->tct_base = SAR_SRAM_TCT_128_BASE;
card->tct_size = (SAR_SRAM_TCT_128_TOP - card->tct_base + 1)
/ SAR_SRAM_TCT_SIZE;
card->rct_base = SAR_SRAM_RCT_128_BASE;
card->rct_size = (SAR_SRAM_RCT_128_TOP - card->rct_base + 1)
/ SAR_SRAM_RCT_SIZE;
card->rt_base = SAR_SRAM_RT_128_BASE;
card->scd_base = SAR_SRAM_SCD_128_BASE;
card->scd_size = (SAR_SRAM_SCD_128_TOP - card->scd_base + 1)
/ SAR_SRAM_SCD_SIZE;
card->tst[0] = SAR_SRAM_TST1_128_BASE;
card->tst[1] = SAR_SRAM_TST2_128_BASE;
card->tst_size = SAR_SRAM_TST1_128_TOP - card->tst[0] + 1;
card->abrst_base = SAR_SRAM_ABRSTD_128_BASE;
card->abrst_size = SAR_ABRSTD_SIZE_8K;
card->fifo_base = SAR_SRAM_FIFO_128_BASE;
card->fifo_size = SAR_RXFD_SIZE_32K;
} else {
card->tct_base = SAR_SRAM_TCT_32_BASE;
card->tct_size = (SAR_SRAM_TCT_32_TOP - card->tct_base + 1)
/ SAR_SRAM_TCT_SIZE;
card->rct_base = SAR_SRAM_RCT_32_BASE;
card->rct_size = (SAR_SRAM_RCT_32_TOP - card->rct_base + 1)
/ SAR_SRAM_RCT_SIZE;
card->rt_base = SAR_SRAM_RT_32_BASE;
card->scd_base = SAR_SRAM_SCD_32_BASE;
card->scd_size = (SAR_SRAM_SCD_32_TOP - card->scd_base + 1)
/ SAR_SRAM_SCD_SIZE;
card->tst[0] = SAR_SRAM_TST1_32_BASE;
card->tst[1] = SAR_SRAM_TST2_32_BASE;
card->tst_size = (SAR_SRAM_TST1_32_TOP - card->tst[0] + 1);
card->abrst_base = SAR_SRAM_ABRSTD_32_BASE;
card->abrst_size = SAR_ABRSTD_SIZE_1K;
card->fifo_base = SAR_SRAM_FIFO_32_BASE;
card->fifo_size = SAR_RXFD_SIZE_4K;
}
/* Initialize TCT */
for (i = 0; i < card->tct_size; i++) {
write_sram(card, i * SAR_SRAM_TCT_SIZE + 0, 0);
write_sram(card, i * SAR_SRAM_TCT_SIZE + 1, 0);
write_sram(card, i * SAR_SRAM_TCT_SIZE + 2, 0);
write_sram(card, i * SAR_SRAM_TCT_SIZE + 3, 0);
write_sram(card, i * SAR_SRAM_TCT_SIZE + 4, 0);
write_sram(card, i * SAR_SRAM_TCT_SIZE + 5, 0);
write_sram(card, i * SAR_SRAM_TCT_SIZE + 6, 0);
write_sram(card, i * SAR_SRAM_TCT_SIZE + 7, 0);
}
/* Initialize RCT */
for (i = 0; i < card->rct_size; i++) {
write_sram(card, card->rct_base + i * SAR_SRAM_RCT_SIZE,
(u32) SAR_RCTE_RAWCELLINTEN);
write_sram(card, card->rct_base + i * SAR_SRAM_RCT_SIZE + 1,
(u32) 0);
write_sram(card, card->rct_base + i * SAR_SRAM_RCT_SIZE + 2,
(u32) 0);
write_sram(card, card->rct_base + i * SAR_SRAM_RCT_SIZE + 3,
(u32) 0xffffffff);
}
writel((SAR_FBQ0_LOW << 28) | 0x00000000 | 0x00000000 |
(SAR_FB_SIZE_0 / 48), SAR_REG_FBQS0);
writel((SAR_FBQ1_LOW << 28) | 0x00000000 | 0x00000000 |
(SAR_FB_SIZE_1 / 48), SAR_REG_FBQS1);
writel((SAR_FBQ2_LOW << 28) | 0x00000000 | 0x00000000 |
(SAR_FB_SIZE_2 / 48), SAR_REG_FBQS2);
writel((SAR_FBQ3_LOW << 28) | 0x00000000 | 0x00000000 |
(SAR_FB_SIZE_3 / 48), SAR_REG_FBQS3);
/* Initialize rate table */
for (i = 0; i < 256; i++) {
write_sram(card, card->rt_base + i, log_to_rate[i]);
}
for (i = 0; i < 128; i++) {
unsigned int tmp;
tmp = rate_to_log[(i << 2) + 0] << 0;
tmp |= rate_to_log[(i << 2) + 1] << 8;
tmp |= rate_to_log[(i << 2) + 2] << 16;
tmp |= rate_to_log[(i << 2) + 3] << 24;
write_sram(card, card->rt_base + 256 + i, tmp);
}
#if 0 /* Fill RDF and AIR tables. */
for (i = 0; i < 128; i++) {
unsigned int tmp;
tmp = RDF[0][(i << 1) + 0] << 16;
tmp |= RDF[0][(i << 1) + 1] << 0;
write_sram(card, card->rt_base + 512 + i, tmp);
}
for (i = 0; i < 128; i++) {
unsigned int tmp;
tmp = AIR[0][(i << 1) + 0] << 16;
tmp |= AIR[0][(i << 1) + 1] << 0;
write_sram(card, card->rt_base + 640 + i, tmp);
}
#endif
IPRINTK("%s: initialize rate table ...\n", card->name);
writel(card->rt_base << 2, SAR_REG_RTBL);
/* Initialize TSTs */
IPRINTK("%s: initialize TST ...\n", card->name);
card->tst_free = card->tst_size - 2; /* last two are jumps */
for (i = card->tst[0]; i < card->tst[0] + card->tst_size - 2; i++)
write_sram(card, i, TSTE_OPC_VAR);
write_sram(card, i++, TSTE_OPC_JMP | (card->tst[0] << 2));
idt77252_sram_write_errors = 1;
write_sram(card, i++, TSTE_OPC_JMP | (card->tst[1] << 2));
idt77252_sram_write_errors = 0;
for (i = card->tst[1]; i < card->tst[1] + card->tst_size - 2; i++)
write_sram(card, i, TSTE_OPC_VAR);
write_sram(card, i++, TSTE_OPC_JMP | (card->tst[1] << 2));
idt77252_sram_write_errors = 1;
write_sram(card, i++, TSTE_OPC_JMP | (card->tst[0] << 2));
idt77252_sram_write_errors = 0;
card->tst_index = 0;
writel(card->tst[0] << 2, SAR_REG_TSTB);
/* Initialize ABRSTD and Receive FIFO */
IPRINTK("%s: initialize ABRSTD ...\n", card->name);
writel(card->abrst_size | (card->abrst_base << 2),
SAR_REG_ABRSTD);
IPRINTK("%s: initialize receive fifo ...\n", card->name);
writel(card->fifo_size | (card->fifo_base << 2),
SAR_REG_RXFD);
IPRINTK("%s: SRAM initialization complete.\n", card->name);
return 0;
}
static int
init_card(struct atm_dev *dev)
{
struct idt77252_dev *card = dev->dev_data;
struct pci_dev *pcidev = card->pcidev;
unsigned long tmpl, modl;
unsigned int linkrate, rsvdcr;
unsigned int tst_entries;
struct net_device *tmp;
char tname[10];
u32 size;
u_char pci_byte;
u32 conf;
int i, k;
if (test_bit(IDT77252_BIT_INIT, &card->flags)) {
printk("Error: SAR already initialized.\n");
return -1;
}
/*****************************************************************/
/* P C I C O N F I G U R A T I O N */
/*****************************************************************/
/* Set PCI Retry-Timeout and TRDY timeout */
IPRINTK("%s: Checking PCI retries.\n", card->name);
if (pci_read_config_byte(pcidev, 0x40, &pci_byte) != 0) {
printk("%s: can't read PCI retry timeout.\n", card->name);
deinit_card(card);
return -1;
}
if (pci_byte != 0) {
IPRINTK("%s: PCI retry timeout: %d, set to 0.\n",
card->name, pci_byte);
if (pci_write_config_byte(pcidev, 0x40, 0) != 0) {
printk("%s: can't set PCI retry timeout.\n",
card->name);
deinit_card(card);
return -1;
}
}
IPRINTK("%s: Checking PCI TRDY.\n", card->name);
if (pci_read_config_byte(pcidev, 0x41, &pci_byte) != 0) {
printk("%s: can't read PCI TRDY timeout.\n", card->name);
deinit_card(card);
return -1;
}
if (pci_byte != 0) {
IPRINTK("%s: PCI TRDY timeout: %d, set to 0.\n",
card->name, pci_byte);
if (pci_write_config_byte(pcidev, 0x41, 0) != 0) {
printk("%s: can't set PCI TRDY timeout.\n", card->name);
deinit_card(card);
return -1;
}
}
/* Reset Timer register */
if (readl(SAR_REG_STAT) & SAR_STAT_TMROF) {
printk("%s: resetting timer overflow.\n", card->name);
writel(SAR_STAT_TMROF, SAR_REG_STAT);
}
IPRINTK("%s: Request IRQ ... ", card->name);
if (request_irq(pcidev->irq, idt77252_interrupt, SA_INTERRUPT|SA_SHIRQ,
card->name, card) != 0) {
printk("%s: can't allocate IRQ.\n", card->name);
deinit_card(card);
return -1;
}
IPRINTK("got %d.\n", pcidev->irq);
/*****************************************************************/
/* C H E C K A N D I N I T S R A M */
/*****************************************************************/
IPRINTK("%s: Initializing SRAM\n", card->name);
/* preset size of connecton table, so that init_sram() knows about it */
conf = SAR_CFG_TX_FIFO_SIZE_9 | /* Use maximum fifo size */
SAR_CFG_RXSTQ_SIZE_8k | /* Receive Status Queue is 8k */
SAR_CFG_IDLE_CLP | /* Set CLP on idle cells */
#ifndef CONFIG_ATM_IDT77252_SEND_IDLE
SAR_CFG_NO_IDLE | /* Do not send idle cells */
#endif
0;
if (card->sramsize == (512 * 1024))
conf |= SAR_CFG_CNTBL_1k;
else
conf |= SAR_CFG_CNTBL_512;
switch (vpibits) {
case 0:
conf |= SAR_CFG_VPVCS_0;
break;
default:
case 1:
conf |= SAR_CFG_VPVCS_1;
break;
case 2:
conf |= SAR_CFG_VPVCS_2;
break;
case 8:
conf |= SAR_CFG_VPVCS_8;
break;
}
writel(readl(SAR_REG_CFG) | conf, SAR_REG_CFG);
if (init_sram(card) < 0)
return -1;
/********************************************************************/
/* A L L O C R A M A N D S E T V A R I O U S T H I N G S */
/********************************************************************/
/* Initialize TSQ */
if (0 != init_tsq(card)) {
deinit_card(card);
return -1;
}
/* Initialize RSQ */
if (0 != init_rsq(card)) {
deinit_card(card);
return -1;
}
card->vpibits = vpibits;
if (card->sramsize == (512 * 1024)) {
card->vcibits = 10 - card->vpibits;
} else {
card->vcibits = 9 - card->vpibits;
}
card->vcimask = 0;
for (k = 0, i = 1; k < card->vcibits; k++) {
card->vcimask |= i;
i <<= 1;
}
IPRINTK("%s: Setting VPI/VCI mask to zero.\n", card->name);
writel(0, SAR_REG_VPM);
/* Little Endian Order */
writel(0, SAR_REG_GP);
/* Initialize RAW Cell Handle Register */
card->raw_cell_hnd = pci_alloc_consistent(card->pcidev, 2 * sizeof(u32),
&card->raw_cell_paddr);
if (!card->raw_cell_hnd) {
printk("%s: memory allocation failure.\n", card->name);
deinit_card(card);
return -1;
}
memset(card->raw_cell_hnd, 0, 2 * sizeof(u32));
writel(card->raw_cell_paddr, SAR_REG_RAWHND);
IPRINTK("%s: raw cell handle is at 0x%p.\n", card->name,
card->raw_cell_hnd);
size = sizeof(struct vc_map *) * card->tct_size;
IPRINTK("%s: allocate %d byte for VC map.\n", card->name, size);
if (NULL == (card->vcs = vmalloc(size))) {
printk("%s: memory allocation failure.\n", card->name);
deinit_card(card);
return -1;
}
memset(card->vcs, 0, size);
size = sizeof(struct vc_map *) * card->scd_size;
IPRINTK("%s: allocate %d byte for SCD to VC mapping.\n",
card->name, size);
if (NULL == (card->scd2vc = vmalloc(size))) {
printk("%s: memory allocation failure.\n", card->name);
deinit_card(card);
return -1;
}
memset(card->scd2vc, 0, size);
size = sizeof(struct tst_info) * (card->tst_size - 2);
IPRINTK("%s: allocate %d byte for TST to VC mapping.\n",
card->name, size);
if (NULL == (card->soft_tst = vmalloc(size))) {
printk("%s: memory allocation failure.\n", card->name);
deinit_card(card);
return -1;
}
for (i = 0; i < card->tst_size - 2; i++) {
card->soft_tst[i].tste = TSTE_OPC_VAR;
card->soft_tst[i].vc = NULL;
}
if (dev->phy == NULL) {
printk("%s: No LT device defined.\n", card->name);
deinit_card(card);
return -1;
}
if (dev->phy->ioctl == NULL) {
printk("%s: LT had no IOCTL funtion defined.\n", card->name);
deinit_card(card);
return -1;
}
#ifdef CONFIG_ATM_IDT77252_USE_SUNI
/*
* this is a jhs hack to get around special functionality in the
* phy driver for the atecom hardware; the functionality doesn't
* exist in the linux atm suni driver
*
* it isn't the right way to do things, but as the guy from NIST
* said, talking about their measurement of the fine structure
* constant, "it's good enough for government work."
*/
linkrate = 149760000;
#endif
card->link_pcr = (linkrate / 8 / 53);
printk("%s: Linkrate on ATM line : %u bit/s, %u cell/s.\n",
card->name, linkrate, card->link_pcr);
#ifdef CONFIG_ATM_IDT77252_SEND_IDLE
card->utopia_pcr = card->link_pcr;
#else
card->utopia_pcr = (160000000 / 8 / 54);
#endif
rsvdcr = 0;
if (card->utopia_pcr > card->link_pcr)
rsvdcr = card->utopia_pcr - card->link_pcr;
tmpl = (unsigned long) rsvdcr * ((unsigned long) card->tst_size - 2);
modl = tmpl % (unsigned long)card->utopia_pcr;
tst_entries = (int) (tmpl / (unsigned long)card->utopia_pcr);
if (modl)
tst_entries++;
card->tst_free -= tst_entries;
fill_tst(card, NULL, tst_entries, TSTE_OPC_NULL);
#ifdef HAVE_EEPROM
idt77252_eeprom_init(card);
printk("%s: EEPROM: %02x:", card->name,
idt77252_eeprom_read_status(card));
for (i = 0; i < 0x80; i++) {
printk(" %02x",
idt77252_eeprom_read_byte(card, i)
);
}
printk("\n");
#endif /* HAVE_EEPROM */
/*
* XXX: <hack>
*/
sprintf(tname, "eth%d", card->index);
tmp = dev_get_by_name(tname); /* jhs: was "tmp = dev_get(tname);" */
if (tmp) {
memcpy(card->atmdev->esi, tmp->dev_addr, 6);
printk("%s: ESI %02x:%02x:%02x:%02x:%02x:%02x\n",
card->name, card->atmdev->esi[0], card->atmdev->esi[1],
card->atmdev->esi[2], card->atmdev->esi[3],
card->atmdev->esi[4], card->atmdev->esi[5]);
}
/*
* XXX: </hack>
*/
/* Set Maximum Deficit Count for now. */
writel(0xffff, SAR_REG_MDFCT);
set_bit(IDT77252_BIT_INIT, &card->flags);
XPRINTK("%s: IDT77252 ABR SAR initialization complete.\n", card->name);
return 0;
}
/*****************************************************************************/
/* */
/* Probing of IDT77252 ABR SAR */
/* */
/*****************************************************************************/
static int
preset_idt77252(struct idt77252_dev *card)
{
u16 pci_command;
/*****************************************************************/
/* P C I C O N F I G U R A T I O N */
/*****************************************************************/
XPRINTK("%s: Enable PCI master and memory access for SAR.\n",
card->name);
if (pci_read_config_word(card->pcidev, PCI_COMMAND, &pci_command)) {
printk("%s: can't read PCI_COMMAND.\n", card->name);
deinit_card(card);
return -1;
}
if (!(pci_command & PCI_COMMAND_IO)) {
printk("%s: PCI_COMMAND: %04x (???)\n",
card->name, pci_command);
deinit_card(card);
return (-1);
}
pci_command |= (PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER);
if (pci_write_config_word(card->pcidev, PCI_COMMAND, pci_command)) {
printk("%s: can't write PCI_COMMAND.\n", card->name);
deinit_card(card);
return -1;
}
/*****************************************************************/
/* G E N E R I C R E S E T */
/*****************************************************************/
/* Software reset */
writel(SAR_CFG_SWRST, SAR_REG_CFG);
mdelay(1);
writel(0, SAR_REG_CFG);
IPRINTK("%s: Software resetted.\n", card->name);
return 0;
}
unsigned long
probe_sram(struct idt77252_dev *card)
{
u32 data, addr;
writel(0, SAR_REG_DR0);
writel(SAR_CMD_WRITE_SRAM | (0 << 2), SAR_REG_CMD);
for (addr = 0x4000; addr < 0x80000; addr += 0x4000) {
writel(0xdeadbeef, SAR_REG_DR0);
writel(SAR_CMD_WRITE_SRAM | (addr << 2), SAR_REG_CMD);
writel(SAR_CMD_READ_SRAM | (0 << 2), SAR_REG_CMD);
data = readl(SAR_REG_DR0);
if (data != 0)
break;
}
return addr * sizeof(u32);
}
int
idt77252_probe(void)
{
struct idt77252_dev **last, *card;
struct pci_dev *pcidev = NULL;
struct atm_dev *dev;
ushort revision = 0;
int i, index = 0;
last = &idt77252_chain;
if (!pci_present()) {
printk(KERN_NOTICE "idt77252: no PCI subsystem found.\n");
return -ENODEV;
}
while ((pcidev = pci_find_device(PCI_VENDOR_ID_IDT,
PCI_DEVICE_ID_IDT_IDT77252,
pcidev))) {
unsigned long membase, srambase;
if (pci_read_config_word(pcidev, PCI_REVISION_ID, &revision)) {
printk("idt77252-%d: can't read PCI_REVISION_ID\n",
index);
continue;
}
card = kmalloc(sizeof(struct idt77252_dev), GFP_KERNEL);
if (!card) {
printk("idt77252-%d: can't allocate private data\n",
index);
continue;
}
memset(card, 0, sizeof(struct idt77252_dev));
card->revision = revision;
card->index = index;
card->pcidev = pcidev;
sprintf(card->name, "idt77252-%d", card->index);
card->tqueue.routine = idt77252_softint;
card->tqueue.data = (void *)card;
membase = pci_resource_start(pcidev, 1);
srambase = pci_resource_start(pcidev, 2);
init_MUTEX(&card->mutex);
spin_lock_init(&card->cmd_lock);
spin_lock_init(&card->tst_lock);
card->tst_timer.data = (unsigned long)card;
card->tst_timer.function = tst_timer;
init_timer(&card->tst_timer);
/* Do the I/O remapping... */
card->membase = (unsigned long) ioremap(membase, 1024);
if (!card->membase) {
printk("%s: can't ioremap() membase\n", card->name);
kfree(card);
continue;
}
if (preset_idt77252(card)) {
printk("%s: preset failed\n", card->name);
iounmap((void *) card->membase);
kfree(card);
continue;
}
dev = atm_dev_register("idt77252", &idt77252_ops, -1, 0);
if (!dev) {
printk("%s: can't register atm device\n", card->name);
iounmap((void *) card->membase);
kfree(card);
continue;
}
dev->dev_data = card;
card->atmdev = dev;
#ifdef CONFIG_ATM_IDT77252_USE_SUNI
suni_init(dev);
if (!dev->phy) {
printk("%s: can't init SUNI\n", card->name);
deinit_card(card);
kfree(card);
continue;
}
#endif /* CONFIG_ATM_IDT77252_USE_SUNI */
card->sramsize = probe_sram(card);
for (i = 0; i < 4; i++) {
card->fbq[i] = (unsigned long)
ioremap(srambase | 0x200000 | (i << 18), 4);
if (!card->fbq[i]) {
printk("%s: can't ioremap() FBQ%d\n",
card->name, i);
deinit_card(card);
kfree(card);
goto next;
}
}
printk("%s: ABR SAR (Rev %c): MEM %08lx SRAM %08lx [%u KB]\n",
card->name, ((revision > 1) && (revision < 25)) ?
'A' + revision - 1 : '?',
membase, srambase, card->sramsize / 1024);
if (init_card(dev)) {
printk("%s: init_card failed\n", card->name);
deinit_card(card);
kfree(card);
continue;
}
dev->ci_range.vpi_bits = card->vpibits;
dev->ci_range.vci_bits = card->vcibits;
dev->link_rate = card->link_pcr;
if (dev->phy->start)
dev->phy->start(dev);
if (idt77252_dev_open(card)) {
printk("%s: dev_open failed\n", card->name);
if (dev->phy->stop)
dev->phy->stop(dev);
deinit_card(card);
kfree(card);
continue;
}
*last = card;
last = &card->next;
index++;
next:
}
return index;
}
#ifdef MODULE
MODULE_PARM(vpibits, "i");
MODULE_AUTHOR("Eddie C. Dost <ecd@atecom.com>");
MODULE_DESCRIPTION("IDT77252 ABR SAR Driver");
#ifdef DEBUG
MODULE_PARM(debug, "i");
#endif
int
init_module(void)
{
int v;
printk("idt77252 init_module: %s at %p\n", __FUNCTION__, init_module);
/*
* this modification is somewhat silly, as atmdev_init.c doesn't
* check for EIO, it only accumulates the return value in the sum
* of atm adaptors found.
*/
v = idt77252_probe();
if (v < 0)
return -EIO;
return 0;
}
void
cleanup_module(void)
{
struct idt77252_dev *card;
struct atm_dev *dev;
while (idt77252_chain) {
card = idt77252_chain;
dev = card->atmdev;
idt77252_chain = card->next;
if (dev->phy->stop)
dev->phy->stop(dev);
deinit_card(card);
kfree(card);
}
DIPRINTK("idt77252: finished cleanup-module().\n");
}
#else
int __init idt77252_detect(void)
{
int v;
v = idt77252_probe();
if (v < 0)
return -EIO;
else
return v;
}
#endif /* MODULE */
/*******************************************************************
* ident "$Id: idt77252.h,v 1.1 2001/11/05 21:52:22 ecd Exp $"
*
* $Author: ecd $
* $Date: 2001/11/05 21:52:22 $
*
* Copyright (c) 2000 ATecoM GmbH
*
* The author may be reached at ecd@atecom.com.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
* NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 675 Mass Ave, Cambridge, MA 02139, USA.
*
*******************************************************************/
#ifndef _IDT77252_H
#define _IDT77252_H 1
#include <linux/ptrace.h>
#include <linux/skbuff.h>
/*****************************************************************************/
/* */
/* Makros */
/* */
/*****************************************************************************/
#define VPCI2VC(card, vpi, vci) \
(((vpi) << card->vcibits) | ((vci) & card->vcimask))
/*****************************************************************************/
/* */
/* DEBUGGING definitions */
/* */
/*****************************************************************************/
#define DBG_TINY 0x00000200
#define DBG_GENERAL 0x00000100
#define DBG_XGENERAL 0x00000080
#define DBG_INIT 0x00000040
#define DBG_DEINIT 0x00000020
#define DBG_INTERRUPT 0x00000010
#define DBG_OPEN_CONN 0x00000008
#define DBG_CLOSE_CONN 0x00000004
#define DBG_RX_DATA 0x00000002
#define DBG_TX_DATA 0x00000001
#ifdef DEBUG
#define CPRINTK(args...) do { if (debug & DBG_CLOSE_CONN) printk(args); } while(0)
#define OPRINTK(args...) do { if (debug & DBG_OPEN_CONN) printk(args); } while(0)
#define IPRINTK(args...) do { if (debug & DBG_INIT) printk(args); } while(0)
#define INTPRINTK(args...) do { if (debug & DBG_INTERRUPT) printk(args); } while(0)
#define DIPRINTK(args...) do { if (debug & DBG_DEINIT) printk(args); } while(0)
#define TXPRINTK(args...) do { if (debug & DBG_TX_DATA) printk(args); } while(0)
#define RXPRINTK(args...) do { if (debug & DBG_RX_DATA) printk(args); } while(0)
#define XPRINTK(args...) do { if (debug & DBG_XGENERAL) printk(args); } while(0)
#define DPRINTK(args...) do { if (debug & DBG_GENERAL) printk(args); } while(0)
#define NPRINTK(args...) do { if (debug & DBG_TINY) printk(args); } while(0)
#else
#define CPRINTK(args...) do { } while(0)
#define OPRINTK(args...) do { } while(0)
#define IPRINTK(args...) do { } while(0)
#define INTPRINTK(args...) do { } while(0)
#define DIPRINTK(args...) do { } while(0)
#define TXPRINTK(args...) do { } while(0)
#define RXPRINTK(args...) do { } while(0)
#define XPRINTK(args...) do { } while(0)
#define DPRINTK(args...) do { } while(0)
#define NPRINTK(args...) do { } while(0)
#endif
#define SCHED_UBR0 0
#define SCHED_UBR 1
#define SCHED_VBR 2
#define SCHED_ABR 3
#define SCHED_CBR 4
#define SCQFULL_TIMEOUT HZ
/*****************************************************************************/
/* */
/* Free Buffer Queue Layout */
/* */
/*****************************************************************************/
#define SAR_FB_SIZE_0 (2048 - 256)
#define SAR_FB_SIZE_1 (4096 - 256)
#define SAR_FB_SIZE_2 (8192 - 256)
#define SAR_FB_SIZE_3 (16384 - 256)
#define SAR_FBQ0_LOW 4
#define SAR_FBQ0_HIGH 8
#define SAR_FBQ1_LOW 2
#define SAR_FBQ1_HIGH 4
#define SAR_FBQ2_LOW 1
#define SAR_FBQ2_HIGH 2
#define SAR_FBQ3_LOW 1
#define SAR_FBQ3_HIGH 2
#if 0
#define SAR_TST_RESERVED 44 /* Num TST reserved for UBR/ABR/VBR */
#else
#define SAR_TST_RESERVED 0 /* Num TST reserved for UBR/ABR/VBR */
#endif
#define TCT_CBR 0x00000000
#define TCT_UBR 0x00000000
#define TCT_VBR 0x40000000
#define TCT_ABR 0x80000000
#define TCT_TYPE 0xc0000000
#define TCT_RR 0x20000000
#define TCT_LMCR 0x08000000
#define TCT_SCD_MASK 0x0007ffff
#define TCT_TSIF 0x00004000
#define TCT_HALT 0x80000000
#define TCT_IDLE 0x40000000
#define TCT_FLAG_UBR 0x80000000
/*****************************************************************************/
/* */
/* Structure describing an IDT77252 */
/* */
/*****************************************************************************/
struct scqe
{
u32 word_1;
u32 word_2;
u32 word_3;
u32 word_4;
};
#define SCQ_ENTRIES 64
#define SCQ_SIZE (SCQ_ENTRIES * sizeof(struct scqe))
#define SCQ_MASK (SCQ_SIZE - 1)
struct scq_info
{
struct scqe *base;
struct scqe *next;
struct scqe *last;
dma_addr_t paddr;
spinlock_t lock;
atomic_t used;
unsigned long trans_start;
unsigned long scd;
spinlock_t skblock;
struct sk_buff_head transmit;
struct sk_buff_head pending;
};
struct rx_pool {
struct sk_buff *first;
struct sk_buff **last;
unsigned int len;
unsigned int count;
};
struct aal1 {
unsigned int total;
unsigned int count;
struct sk_buff *data;
unsigned char sequence;
};
struct rate_estimator {
struct timer_list timer;
unsigned int interval;
unsigned int ewma_log;
u64 cells;
u64 last_cells;
long avcps;
u32 cps;
u32 maxcps;
};
struct vc_map {
unsigned int index;
unsigned long flags;
#define VCF_TX 0
#define VCF_RX 1
#define VCF_IDLE 2
#define VCF_RSV 3
unsigned int class;
u8 init_er;
u8 lacr;
u8 max_er;
unsigned int ntste;
spinlock_t lock;
struct atm_vcc *tx_vcc;
struct atm_vcc *rx_vcc;
struct idt77252_dev *card;
struct scq_info *scq; /* To keep track of the SCQ */
struct rate_estimator *estimator;
int scd_index;
union {
struct rx_pool rx_pool;
struct aal1 aal1;
} rcv;
};
/*****************************************************************************/
/* */
/* RCTE - Receive Connection Table Entry */
/* */
/*****************************************************************************/
struct rct_entry
{
u32 word_1;
u32 buffer_handle;
u32 dma_address;
u32 aal5_crc32;
};
/*****************************************************************************/
/* */
/* RSQ - Receive Status Queue */
/* */
/*****************************************************************************/
#define SAR_RSQE_VALID 0x80000000
#define SAR_RSQE_IDLE 0x40000000
#define SAR_RSQE_BUF_MASK 0x00030000
#define SAR_RSQE_BUF_ASGN 0x00008000
#define SAR_RSQE_NZGFC 0x00004000
#define SAR_RSQE_EPDU 0x00002000
#define SAR_RSQE_BUF_CONT 0x00001000
#define SAR_RSQE_EFCIE 0x00000800
#define SAR_RSQE_CLP 0x00000400
#define SAR_RSQE_CRC 0x00000200
#define SAR_RSQE_CELLCNT 0x000001FF
#define RSQSIZE 8192
#define RSQ_NUM_ENTRIES (RSQSIZE / 16)
#define RSQ_ALIGNMENT 8192
struct rsq_entry {
u32 word_1;
u32 word_2;
u32 word_3;
u32 word_4;
};
struct rsq_info {
struct rsq_entry *base;
struct rsq_entry *next;
struct rsq_entry *last;
dma_addr_t paddr;
} rsq_info;
/*****************************************************************************/
/* */
/* TSQ - Transmit Status Queue */
/* */
/*****************************************************************************/
#define SAR_TSQE_INVALID 0x80000000
#define SAR_TSQE_TIMESTAMP 0x00FFFFFF
#define SAR_TSQE_TYPE 0x60000000
#define SAR_TSQE_TYPE_TIMER 0x00000000
#define SAR_TSQE_TYPE_TSR 0x20000000
#define SAR_TSQE_TYPE_IDLE 0x40000000
#define SAR_TSQE_TYPE_TBD_COMP 0x60000000
#define SAR_TSQE_TAG(stat) (((stat) >> 24) & 0x1f)
#define TSQSIZE 8192
#define TSQ_NUM_ENTRIES 1024
#define TSQ_ALIGNMENT 8192
struct tsq_entry
{
u32 word_1;
u32 word_2;
};
struct tsq_info
{
struct tsq_entry *base;
struct tsq_entry *next;
struct tsq_entry *last;
dma_addr_t paddr;
};
struct tst_info
{
struct vc_map *vc;
u32 tste;
};
#define TSTE_MASK 0x601fffff
#define TSTE_OPC_MASK 0x60000000
#define TSTE_OPC_NULL 0x00000000
#define TSTE_OPC_CBR 0x20000000
#define TSTE_OPC_VAR 0x40000000
#define TSTE_OPC_JMP 0x60000000
#define TSTE_PUSH_IDLE 0x01000000
#define TSTE_PUSH_ACTIVE 0x02000000
#define TST_SWITCH_DONE 0
#define TST_SWITCH_PENDING 1
#define TST_SWITCH_WAIT 2
#define FBQ_SHIFT 9
#define FBQ_SIZE (1 << FBQ_SHIFT)
#define FBQ_MASK (FBQ_SIZE - 1)
struct sb_pool
{
unsigned int index;
struct sk_buff *skb[FBQ_SIZE];
};
#define POOL_HANDLE(queue, index) (((queue + 1) << 16) | (index))
#define POOL_QUEUE(handle) (((handle) >> 16) - 1)
#define POOL_INDEX(handle) ((handle) & 0xffff)
struct idt77252_dev
{
struct tsq_info tsq; /* Transmit Status Queue */
struct rsq_info rsq; /* Receive Status Queue */
struct pci_dev *pcidev; /* PCI handle (desriptor) */
struct atm_dev *atmdev; /* ATM device desriptor */
unsigned long membase; /* SAR's memory base address */
unsigned long srambase; /* SAR's sram base address */
unsigned long fbq[4]; /* FBQ fill addresses */
struct semaphore mutex;
spinlock_t cmd_lock; /* for r/w utility/sram */
unsigned long softstat;
unsigned long flags; /* see blow */
struct tq_struct tqueue;
unsigned long tct_base; /* TCT base address in SRAM */
unsigned long rct_base; /* RCT base address in SRAM */
unsigned long rt_base; /* Rate Table base in SRAM */
unsigned long scd_base; /* SCD base address in SRAM */
unsigned long tst[2]; /* TST base address in SRAM */
unsigned long abrst_base; /* ABRST base address in SRAM */
unsigned long fifo_base; /* RX FIFO base in SRAM */
unsigned long irqstat[16];
unsigned int sramsize; /* SAR's sram size */
unsigned int tct_size; /* total TCT entries */
unsigned int rct_size; /* total RCT entries */
unsigned int scd_size; /* length of SCD */
unsigned int tst_size; /* total TST entries */
unsigned int tst_free; /* free TSTEs in TST */
unsigned int abrst_size; /* size of ABRST in words */
unsigned int fifo_size; /* size of RX FIFO in words */
unsigned int vpibits; /* Bits used for VPI index */
unsigned int vcibits; /* Bits used for VCI index */
unsigned int vcimask; /* Mask for VCI index */
unsigned int utopia_pcr; /* Utopia Itf's Cell Rate */
unsigned int link_pcr; /* PHY's Peek Cell Rate */
struct vc_map **vcs; /* Open Connections */
struct vc_map **scd2vc; /* SCD to Connection map */
struct tst_info *soft_tst; /* TST to Connection map */
unsigned int tst_index; /* Current TST in use */
struct timer_list tst_timer;
spinlock_t tst_lock;
unsigned long tst_state;
struct sb_pool sbpool[4]; /* Pool of RX skbuffs */
struct sk_buff *raw_cell_head; /* Pointer to raw cell queue */
u32 *raw_cell_hnd; /* Pointer to RCQ handle */
dma_addr_t raw_cell_paddr;
int index; /* SAR's ID */
int revision; /* chip revision */
char name[16]; /* Device name */
struct idt77252_dev *next;
};
/* definition for flag field above */
#define IDT77252_BIT_INIT 1
#define IDT77252_BIT_INTERRUPT 2
#define ATM_CELL_PAYLOAD 48
#define FREEBUF_ALIGNMENT 16
/*****************************************************************************/
/* */
/* Makros */
/* */
/*****************************************************************************/
#define ALIGN_ADDRESS(addr, alignment) \
((((u32)(addr)) + (((u32)(alignment))-1)) & ~(((u32)(alignment)) - 1))
/*****************************************************************************/
/* */
/* ABR SAR Network operation Register */
/* */
/*****************************************************************************/
#define SAR_REG_DR0 (card->membase + 0x00)
#define SAR_REG_DR1 (card->membase + 0x04)
#define SAR_REG_DR2 (card->membase + 0x08)
#define SAR_REG_DR3 (card->membase + 0x0C)
#define SAR_REG_CMD (card->membase + 0x10)
#define SAR_REG_CFG (card->membase + 0x14)
#define SAR_REG_STAT (card->membase + 0x18)
#define SAR_REG_RSQB (card->membase + 0x1C)
#define SAR_REG_RSQT (card->membase + 0x20)
#define SAR_REG_RSQH (card->membase + 0x24)
#define SAR_REG_CDC (card->membase + 0x28)
#define SAR_REG_VPEC (card->membase + 0x2C)
#define SAR_REG_ICC (card->membase + 0x30)
#define SAR_REG_RAWCT (card->membase + 0x34)
#define SAR_REG_TMR (card->membase + 0x38)
#define SAR_REG_TSTB (card->membase + 0x3C)
#define SAR_REG_TSQB (card->membase + 0x40)
#define SAR_REG_TSQT (card->membase + 0x44)
#define SAR_REG_TSQH (card->membase + 0x48)
#define SAR_REG_GP (card->membase + 0x4C)
#define SAR_REG_VPM (card->membase + 0x50)
#define SAR_REG_RXFD (card->membase + 0x54)
#define SAR_REG_RXFT (card->membase + 0x58)
#define SAR_REG_RXFH (card->membase + 0x5C)
#define SAR_REG_RAWHND (card->membase + 0x60)
#define SAR_REG_RXSTAT (card->membase + 0x64)
#define SAR_REG_ABRSTD (card->membase + 0x68)
#define SAR_REG_ABRRQ (card->membase + 0x6C)
#define SAR_REG_VBRRQ (card->membase + 0x70)
#define SAR_REG_RTBL (card->membase + 0x74)
#define SAR_REG_MDFCT (card->membase + 0x78)
#define SAR_REG_TXSTAT (card->membase + 0x7C)
#define SAR_REG_TCMDQ (card->membase + 0x80)
#define SAR_REG_IRCP (card->membase + 0x84)
#define SAR_REG_FBQP0 (card->membase + 0x88)
#define SAR_REG_FBQP1 (card->membase + 0x8C)
#define SAR_REG_FBQP2 (card->membase + 0x90)
#define SAR_REG_FBQP3 (card->membase + 0x94)
#define SAR_REG_FBQS0 (card->membase + 0x98)
#define SAR_REG_FBQS1 (card->membase + 0x9C)
#define SAR_REG_FBQS2 (card->membase + 0xA0)
#define SAR_REG_FBQS3 (card->membase + 0xA4)
#define SAR_REG_FBQWP0 (card->membase + 0xA8)
#define SAR_REG_FBQWP1 (card->membase + 0xAC)
#define SAR_REG_FBQWP2 (card->membase + 0xB0)
#define SAR_REG_FBQWP3 (card->membase + 0xB4)
#define SAR_REG_NOW (card->membase + 0xB8)
/*****************************************************************************/
/* */
/* Commands */
/* */
/*****************************************************************************/
#define SAR_CMD_NO_OPERATION 0x00000000
#define SAR_CMD_OPENCLOSE_CONNECTION 0x20000000
#define SAR_CMD_WRITE_SRAM 0x40000000
#define SAR_CMD_READ_SRAM 0x50000000
#define SAR_CMD_READ_UTILITY 0x80000000
#define SAR_CMD_WRITE_UTILITY 0x90000000
#define SAR_CMD_OPEN_CONNECTION (SAR_CMD_OPENCLOSE_CONNECTION | 0x00080000)
#define SAR_CMD_CLOSE_CONNECTION SAR_CMD_OPENCLOSE_CONNECTION
/*****************************************************************************/
/* */
/* Configuration Register bits */
/* */
/*****************************************************************************/
#define SAR_CFG_SWRST 0x80000000 /* Software reset */
#define SAR_CFG_LOOP 0x40000000 /* Internal Loopback */
#define SAR_CFG_RXPTH 0x20000000 /* Receive Path Enable */
#define SAR_CFG_IDLE_CLP 0x10000000 /* SAR set CLP Bits of Null Cells */
#define SAR_CFG_TX_FIFO_SIZE_1 0x04000000 /* TX FIFO Size = 1 cell */
#define SAR_CFG_TX_FIFO_SIZE_2 0x08000000 /* TX FIFO Size = 2 cells */
#define SAR_CFG_TX_FIFO_SIZE_4 0x0C000000 /* TX FIFO Size = 4 cells */
#define SAR_CFG_TX_FIFO_SIZE_9 0x00000000 /* TX FIFO Size = 9 cells (full) */
#define SAR_CFG_NO_IDLE 0x02000000 /* SAR sends no Null Cells */
#define SAR_CFG_RSVD1 0x01000000 /* Reserved */
#define SAR_CFG_RXSTQ_SIZE_2k 0x00000000 /* RX Stat Queue Size = 2048 byte */
#define SAR_CFG_RXSTQ_SIZE_4k 0x00400000 /* RX Stat Queue Size = 4096 byte */
#define SAR_CFG_RXSTQ_SIZE_8k 0x00800000 /* RX Stat Queue Size = 8192 byte */
#define SAR_CFG_RXSTQ_SIZE_R 0x00C00000 /* RX Stat Queue Size = reserved */
#define SAR_CFG_ICAPT 0x00200000 /* accept Invalid Cells */
#define SAR_CFG_IGGFC 0x00100000 /* Ignore GFC */
#define SAR_CFG_VPVCS_0 0x00000000 /* VPI/VCI Select bit range */
#define SAR_CFG_VPVCS_1 0x00040000 /* VPI/VCI Select bit range */
#define SAR_CFG_VPVCS_2 0x00080000 /* VPI/VCI Select bit range */
#define SAR_CFG_VPVCS_8 0x000C0000 /* VPI/VCI Select bit range */
#define SAR_CFG_CNTBL_1k 0x00000000 /* Connection Table Size */
#define SAR_CFG_CNTBL_4k 0x00010000 /* Connection Table Size */
#define SAR_CFG_CNTBL_16k 0x00020000 /* Connection Table Size */
#define SAR_CFG_CNTBL_512 0x00030000 /* Connection Table Size */
#define SAR_CFG_VPECA 0x00008000 /* VPI/VCI Error Cell Accept */
#define SAR_CFG_RXINT_NOINT 0x00000000 /* No Interrupt on PDU received */
#define SAR_CFG_RXINT_NODELAY 0x00001000 /* Interrupt without delay to host*/
#define SAR_CFG_RXINT_256US 0x00002000 /* Interrupt with delay 256 usec */
#define SAR_CFG_RXINT_505US 0x00003000 /* Interrupt with delay 505 usec */
#define SAR_CFG_RXINT_742US 0x00004000 /* Interrupt with delay 742 usec */
#define SAR_CFG_RAWIE 0x00000800 /* Raw Cell Queue Interrupt Enable*/
#define SAR_CFG_RQFIE 0x00000400 /* RSQ Almost Full Int Enable */
#define SAR_CFG_RSVD2 0x00000200 /* Reserved */
#define SAR_CFG_CACHE 0x00000100 /* DMA on Cache Line Boundary */
#define SAR_CFG_TMOIE 0x00000080 /* Timer Roll Over Int Enable */
#define SAR_CFG_FBIE 0x00000040 /* Free Buffer Queue Int Enable */
#define SAR_CFG_TXEN 0x00000020 /* Transmit Operation Enable */
#define SAR_CFG_TXINT 0x00000010 /* Transmit status Int Enable */
#define SAR_CFG_TXUIE 0x00000008 /* Transmit underrun Int Enable */
#define SAR_CFG_UMODE 0x00000004 /* Utopia Mode Select */
#define SAR_CFG_TXSFI 0x00000002 /* Transmit status Full Int Enable*/
#define SAR_CFG_PHYIE 0x00000001 /* PHY Interrupt Enable */
#define SAR_CFG_TX_FIFO_SIZE_MASK 0x0C000000 /* TX FIFO Size Mask */
#define SAR_CFG_RXSTQSIZE_MASK 0x00C00000
#define SAR_CFG_CNTBL_MASK 0x00030000
#define SAR_CFG_RXINT_MASK 0x00007000
/*****************************************************************************/
/* */
/* Status Register bits */
/* */
/*****************************************************************************/
#define SAR_STAT_FRAC_3 0xF0000000 /* Fraction of Free Buffer Queue 3 */
#define SAR_STAT_FRAC_2 0x0F000000 /* Fraction of Free Buffer Queue 2 */
#define SAR_STAT_FRAC_1 0x00F00000 /* Fraction of Free Buffer Queue 1 */
#define SAR_STAT_FRAC_0 0x000F0000 /* Fraction of Free Buffer Queue 0 */
#define SAR_STAT_TSIF 0x00008000 /* Transmit Status Indicator */
#define SAR_STAT_TXICP 0x00004000 /* Transmit Status Indicator */
#define SAR_STAT_RSVD1 0x00002000 /* Reserved */
#define SAR_STAT_TSQF 0x00001000 /* Transmit Status Queue full */
#define SAR_STAT_TMROF 0x00000800 /* Timer overflow */
#define SAR_STAT_PHYI 0x00000400 /* PHY device Interrupt flag */
#define SAR_STAT_CMDBZ 0x00000200 /* ABR SAR Comand Busy Flag */
#define SAR_STAT_FBQ3A 0x00000100 /* Free Buffer Queue 3 Attention */
#define SAR_STAT_FBQ2A 0x00000080 /* Free Buffer Queue 2 Attention */
#define SAR_STAT_RSQF 0x00000040 /* Receive Status Queue full */
#define SAR_STAT_EPDU 0x00000020 /* End Of PDU Flag */
#define SAR_STAT_RAWCF 0x00000010 /* Raw Cell Flag */
#define SAR_STAT_FBQ1A 0x00000008 /* Free Buffer Queue 1 Attention */
#define SAR_STAT_FBQ0A 0x00000004 /* Free Buffer Queue 0 Attention */
#define SAR_STAT_RSQAF 0x00000002 /* Receive Status Queue almost full*/
#define SAR_STAT_RSVD2 0x00000001 /* Reserved */
/*****************************************************************************/
/* */
/* General Purpose Register bits */
/* */
/*****************************************************************************/
#define SAR_GP_TXNCC_MASK 0xff000000 /* Transmit Negative Credit Count */
#define SAR_GP_EEDI 0x00010000 /* EEPROM Data In */
#define SAR_GP_BIGE 0x00008000 /* Big Endian Operation */
#define SAR_GP_RM_NORMAL 0x00000000 /* Normal handling of RM cells */
#define SAR_GP_RM_TO_RCQ 0x00002000 /* put RM cells into Raw Cell Queue */
#define SAR_GP_RM_RSVD 0x00004000 /* Reserved */
#define SAR_GP_RM_INHIBIT 0x00006000 /* Inhibit update of Connection tab */
#define SAR_GP_PHY_RESET 0x00000008 /* PHY Reset */
#define SAR_GP_EESCLK 0x00000004 /* EEPROM SCLK */
#define SAR_GP_EECS 0x00000002 /* EEPROM Chip Select */
#define SAR_GP_EEDO 0x00000001 /* EEPROM Data Out */
/*****************************************************************************/
/* */
/* SAR local SRAM layout for 128k work SRAM */
/* */
/*****************************************************************************/
#define SAR_SRAM_SCD_SIZE 12
#define SAR_SRAM_TCT_SIZE 8
#define SAR_SRAM_RCT_SIZE 4
#define SAR_SRAM_TCT_128_BASE 0x00000
#define SAR_SRAM_TCT_128_TOP 0x01fff
#define SAR_SRAM_RCT_128_BASE 0x02000
#define SAR_SRAM_RCT_128_TOP 0x02fff
#define SAR_SRAM_FB0_128_BASE 0x03000
#define SAR_SRAM_FB0_128_TOP 0x033ff
#define SAR_SRAM_FB1_128_BASE 0x03400
#define SAR_SRAM_FB1_128_TOP 0x037ff
#define SAR_SRAM_FB2_128_BASE 0x03800
#define SAR_SRAM_FB2_128_TOP 0x03bff
#define SAR_SRAM_FB3_128_BASE 0x03c00
#define SAR_SRAM_FB3_128_TOP 0x03fff
#define SAR_SRAM_SCD_128_BASE 0x04000
#define SAR_SRAM_SCD_128_TOP 0x07fff
#define SAR_SRAM_TST1_128_BASE 0x08000
#define SAR_SRAM_TST1_128_TOP 0x0bfff
#define SAR_SRAM_TST2_128_BASE 0x0c000
#define SAR_SRAM_TST2_128_TOP 0x0ffff
#define SAR_SRAM_ABRSTD_128_BASE 0x10000
#define SAR_SRAM_ABRSTD_128_TOP 0x13fff
#define SAR_SRAM_RT_128_BASE 0x14000
#define SAR_SRAM_RT_128_TOP 0x15fff
#define SAR_SRAM_FIFO_128_BASE 0x18000
#define SAR_SRAM_FIFO_128_TOP 0x1ffff
/*****************************************************************************/
/* */
/* SAR local SRAM layout for 32k work SRAM */
/* */
/*****************************************************************************/
#define SAR_SRAM_TCT_32_BASE 0x00000
#define SAR_SRAM_TCT_32_TOP 0x00fff
#define SAR_SRAM_RCT_32_BASE 0x01000
#define SAR_SRAM_RCT_32_TOP 0x017ff
#define SAR_SRAM_FB0_32_BASE 0x01800
#define SAR_SRAM_FB0_32_TOP 0x01bff
#define SAR_SRAM_FB1_32_BASE 0x01c00
#define SAR_SRAM_FB1_32_TOP 0x01fff
#define SAR_SRAM_FB2_32_BASE 0x02000
#define SAR_SRAM_FB2_32_TOP 0x023ff
#define SAR_SRAM_FB3_32_BASE 0x02400
#define SAR_SRAM_FB3_32_TOP 0x027ff
#define SAR_SRAM_SCD_32_BASE 0x02800
#define SAR_SRAM_SCD_32_TOP 0x03fff
#define SAR_SRAM_TST1_32_BASE 0x04000
#define SAR_SRAM_TST1_32_TOP 0x04fff
#define SAR_SRAM_TST2_32_BASE 0x05000
#define SAR_SRAM_TST2_32_TOP 0x05fff
#define SAR_SRAM_ABRSTD_32_BASE 0x06000
#define SAR_SRAM_ABRSTD_32_TOP 0x067ff
#define SAR_SRAM_RT_32_BASE 0x06800
#define SAR_SRAM_RT_32_TOP 0x06fff
#define SAR_SRAM_FIFO_32_BASE 0x07000
#define SAR_SRAM_FIFO_32_TOP 0x07fff
/*****************************************************************************/
/* */
/* TSR - Transmit Status Request */
/* */
/*****************************************************************************/
#define SAR_TSR_TYPE_TSR 0x80000000
#define SAR_TSR_TYPE_TBD 0x00000000
#define SAR_TSR_TSIF 0x20000000
#define SAR_TSR_TAG_MASK 0x01F00000
/*****************************************************************************/
/* */
/* TBD - Transmit Buffer Descriptor */
/* */
/*****************************************************************************/
#define SAR_TBD_EPDU 0x40000000
#define SAR_TBD_TSIF 0x20000000
#define SAR_TBD_OAM 0x10000000
#define SAR_TBD_AAL0 0x00000000
#define SAR_TBD_AAL34 0x04000000
#define SAR_TBD_AAL5 0x08000000
#define SAR_TBD_GTSI 0x02000000
#define SAR_TBD_TAG_MASK 0x01F00000
#define SAR_TBD_VPI_MASK 0x0FF00000
#define SAR_TBD_VCI_MASK 0x000FFFF0
#define SAR_TBD_VC_MASK (SAR_TBD_VPI_MASK | SAR_TBD_VCI_MASK)
#define SAR_TBD_VPI_SHIFT 20
#define SAR_TBD_VCI_SHIFT 4
/*****************************************************************************/
/* */
/* RXFD - Receive FIFO Descriptor */
/* */
/*****************************************************************************/
#define SAR_RXFD_SIZE_MASK 0x0F000000
#define SAR_RXFD_SIZE_512 0x00000000 /* 512 words */
#define SAR_RXFD_SIZE_1K 0x01000000 /* 1k words */
#define SAR_RXFD_SIZE_2K 0x02000000 /* 2k words */
#define SAR_RXFD_SIZE_4K 0x03000000 /* 4k words */
#define SAR_RXFD_SIZE_8K 0x04000000 /* 8k words */
#define SAR_RXFD_SIZE_16K 0x05000000 /* 16k words */
#define SAR_RXFD_SIZE_32K 0x06000000 /* 32k words */
#define SAR_RXFD_SIZE_64K 0x07000000 /* 64k words */
#define SAR_RXFD_SIZE_128K 0x08000000 /* 128k words */
#define SAR_RXFD_SIZE_256K 0x09000000 /* 256k words */
#define SAR_RXFD_ADDR_MASK 0x001ffc00
/*****************************************************************************/
/* */
/* ABRSTD - ABR + VBR Schedule Tables */
/* */
/*****************************************************************************/
#define SAR_ABRSTD_SIZE_MASK 0x07000000
#define SAR_ABRSTD_SIZE_512 0x00000000 /* 512 words */
#define SAR_ABRSTD_SIZE_1K 0x01000000 /* 1k words */
#define SAR_ABRSTD_SIZE_2K 0x02000000 /* 2k words */
#define SAR_ABRSTD_SIZE_4K 0x03000000 /* 4k words */
#define SAR_ABRSTD_SIZE_8K 0x04000000 /* 8k words */
#define SAR_ABRSTD_SIZE_16K 0x05000000 /* 16k words */
#define SAR_ABRSTD_ADDR_MASK 0x001ffc00
/*****************************************************************************/
/* */
/* RCTE - Receive Connection Table Entry */
/* */
/*****************************************************************************/
#define SAR_RCTE_IL_MASK 0xE0000000 /* inactivity limit */
#define SAR_RCTE_IC_MASK 0x1C000000 /* inactivity count */
#define SAR_RCTE_RSVD 0x02000000 /* reserved */
#define SAR_RCTE_LCD 0x01000000 /* last cell data */
#define SAR_RCTE_CI_VC 0x00800000 /* EFCI in previous cell of VC */
#define SAR_RCTE_FBP_01 0x00000000 /* 1. cell->FBQ0, others->FBQ1 */
#define SAR_RCTE_FBP_1 0x00200000 /* use FBQ 1 for all cells */
#define SAR_RCTE_FBP_2 0x00400000 /* use FBQ 2 for all cells */
#define SAR_RCTE_FBP_3 0x00600000 /* use FBQ 3 for all cells */
#define SAR_RCTE_NZ_GFC 0x00100000 /* non zero GFC in all cell of VC */
#define SAR_RCTE_CONNECTOPEN 0x00080000 /* VC is open */
#define SAR_RCTE_AAL_MASK 0x00070000 /* mask for AAL type field s.b. */
#define SAR_RCTE_RAWCELLINTEN 0x00008000 /* raw cell interrupt enable */
#define SAR_RCTE_RXCONCELLADDR 0x00004000 /* RX constant cell address */
#define SAR_RCTE_BUFFSTAT_MASK 0x00003000 /* buffer status */
#define SAR_RCTE_EFCI 0x00000800 /* EFCI Congestion flag */
#define SAR_RCTE_CLP 0x00000400 /* Cell Loss Priority flag */
#define SAR_RCTE_CRC 0x00000200 /* Recieved CRC Error */
#define SAR_RCTE_CELLCNT_MASK 0x000001FF /* cell Count */
#define SAR_RCTE_AAL0 0x00000000 /* AAL types for ALL field */
#define SAR_RCTE_AAL34 0x00010000
#define SAR_RCTE_AAL5 0x00020000
#define SAR_RCTE_RCQ 0x00030000
#define SAR_RCTE_OAM 0x00040000
#define TCMDQ_START 0x01000000
#define TCMDQ_LACR 0x02000000
#define TCMDQ_START_LACR 0x03000000
#define TCMDQ_INIT_ER 0x04000000
#define TCMDQ_HALT 0x05000000
struct idt77252_skb_prv {
struct scqe tbd; /* Transmit Buffer Descriptor */
u32 pool; /* sb_pool index */
dma_addr_t paddr; /* DMA handle */
void *vaddr; /* DMA virtual address */
unsigned int size; /* DMA buffer size */
struct sk_buff *next; /* next PDU buffer */
};
#define IDT77252_PRV_TBD(skb) \
(((struct idt77252_skb_prv *)(ATM_SKB(skb)+1))->tbd)
#define IDT77252_PRV_POOL(skb) \
(((struct idt77252_skb_prv *)(ATM_SKB(skb)+1))->pool)
#define IDT77252_PRV_PADDR(skb) \
(((struct idt77252_skb_prv *)(ATM_SKB(skb)+1))->paddr)
#define IDT77252_PRV_VADDR(skb) \
(((struct idt77252_skb_prv *)(ATM_SKB(skb)+1))->vaddr)
#define IDT77252_PRV_SIZE(skb) \
(((struct idt77252_skb_prv *)(ATM_SKB(skb)+1))->size)
#define IDT77252_PRV_NEXT(skb) \
(((struct idt77252_skb_prv *)(ATM_SKB(skb)+1))->next)
/*****************************************************************************/
/* */
/* PCI related items */
/* */
/*****************************************************************************/
#ifndef PCI_VENDOR_ID_IDT
#define PCI_VENDOR_ID_IDT 0x111D
#endif /* PCI_VENDOR_ID_IDT */
#ifndef PCI_DEVICE_ID_IDT_IDT77252
#define PCI_DEVICE_ID_IDT_IDT77252 0x0003
#endif /* PCI_DEVICE_ID_IDT_IDT772052 */
#endif /* !(_IDT77252_H) */
/* Do not edit, automatically generated by `./genrtbl'.
*
* Cell Line Rate: 353207.55 (155520000 bps)
*/
static unsigned int log_to_rate[] =
{
/* 000 */ 0x8d022e27, /* cps = 10.02, nrm = 3, interval = 35264.00 */
/* 001 */ 0x8d362e11, /* cps = 10.42, nrm = 3, interval = 33856.00 */
/* 002 */ 0x8d6e2bf8, /* cps = 10.86, nrm = 3, interval = 32512.00 */
/* 003 */ 0x8da82bcf, /* cps = 11.31, nrm = 3, interval = 31200.00 */
/* 004 */ 0x8de42ba8, /* cps = 11.78, nrm = 3, interval = 29952.00 */
/* 005 */ 0x8e242b82, /* cps = 12.28, nrm = 3, interval = 28736.00 */
/* 006 */ 0x8e662b5e, /* cps = 12.80, nrm = 3, interval = 27584.00 */
/* 007 */ 0x8eaa2b3c, /* cps = 13.33, nrm = 3, interval = 26496.00 */
/* 008 */ 0x8ef22b1a, /* cps = 13.89, nrm = 3, interval = 25408.00 */
/* 009 */ 0x8f3e2afa, /* cps = 14.48, nrm = 3, interval = 24384.00 */
/* 010 */ 0x8f8a2adc, /* cps = 15.08, nrm = 3, interval = 23424.00 */
/* 011 */ 0x8fdc2abe, /* cps = 15.72, nrm = 3, interval = 22464.00 */
/* 012 */ 0x90182aa2, /* cps = 16.38, nrm = 3, interval = 21568.00 */
/* 013 */ 0x90422a87, /* cps = 17.03, nrm = 3, interval = 20704.00 */
/* 014 */ 0x90702a6d, /* cps = 17.75, nrm = 3, interval = 19872.00 */
/* 015 */ 0x90a02a54, /* cps = 18.50, nrm = 3, interval = 19072.00 */
/* 016 */ 0x90d22a3c, /* cps = 19.28, nrm = 3, interval = 18304.00 */
/* 017 */ 0x91062a25, /* cps = 20.09, nrm = 3, interval = 17568.00 */
/* 018 */ 0x913c2a0f, /* cps = 20.94, nrm = 3, interval = 16864.00 */
/* 019 */ 0x917427f3, /* cps = 21.81, nrm = 3, interval = 16176.00 */
/* 020 */ 0x91b027ca, /* cps = 22.75, nrm = 3, interval = 15520.00 */
/* 021 */ 0x91ec27a3, /* cps = 23.69, nrm = 3, interval = 14896.00 */
/* 022 */ 0x922c277e, /* cps = 24.69, nrm = 3, interval = 14304.00 */
/* 023 */ 0x926e275a, /* cps = 25.72, nrm = 3, interval = 13728.00 */
/* 024 */ 0x92b42737, /* cps = 26.81, nrm = 3, interval = 13168.00 */
/* 025 */ 0x92fc2716, /* cps = 27.94, nrm = 3, interval = 12640.00 */
/* 026 */ 0x934626f6, /* cps = 29.09, nrm = 3, interval = 12128.00 */
/* 027 */ 0x939426d8, /* cps = 30.31, nrm = 3, interval = 11648.00 */
/* 028 */ 0x93e426bb, /* cps = 31.56, nrm = 3, interval = 11184.00 */
/* 029 */ 0x941e269e, /* cps = 32.94, nrm = 3, interval = 10720.00 */
/* 030 */ 0x944a2683, /* cps = 34.31, nrm = 3, interval = 10288.00 */
/* 031 */ 0x9476266a, /* cps = 35.69, nrm = 3, interval = 9888.00 */
/* 032 */ 0x94a62651, /* cps = 37.19, nrm = 3, interval = 9488.00 */
/* 033 */ 0x94d82639, /* cps = 38.75, nrm = 3, interval = 9104.00 */
/* 034 */ 0x950c6622, /* cps = 40.38, nrm = 4, interval = 8736.00 */
/* 035 */ 0x9544660c, /* cps = 42.12, nrm = 4, interval = 8384.00 */
/* 036 */ 0x957c63ee, /* cps = 43.88, nrm = 4, interval = 8048.00 */
/* 037 */ 0x95b663c6, /* cps = 45.69, nrm = 4, interval = 7728.00 */
/* 038 */ 0x95f4639f, /* cps = 47.62, nrm = 4, interval = 7416.00 */
/* 039 */ 0x96346379, /* cps = 49.62, nrm = 4, interval = 7112.00 */
/* 040 */ 0x96766356, /* cps = 51.69, nrm = 4, interval = 6832.00 */
/* 041 */ 0x96bc6333, /* cps = 53.88, nrm = 4, interval = 6552.00 */
/* 042 */ 0x97046312, /* cps = 56.12, nrm = 4, interval = 6288.00 */
/* 043 */ 0x974e62f3, /* cps = 58.44, nrm = 4, interval = 6040.00 */
/* 044 */ 0x979e62d4, /* cps = 60.94, nrm = 4, interval = 5792.00 */
/* 045 */ 0x97f062b7, /* cps = 63.50, nrm = 4, interval = 5560.00 */
/* 046 */ 0x9822629b, /* cps = 66.12, nrm = 4, interval = 5336.00 */
/* 047 */ 0x984e6280, /* cps = 68.88, nrm = 4, interval = 5120.00 */
/* 048 */ 0x987e6266, /* cps = 71.88, nrm = 4, interval = 4912.00 */
/* 049 */ 0x98ac624e, /* cps = 74.75, nrm = 4, interval = 4720.00 */
/* 050 */ 0x98e06236, /* cps = 78.00, nrm = 4, interval = 4528.00 */
/* 051 */ 0x9914a21f, /* cps = 81.25, nrm = 8, interval = 4344.00 */
/* 052 */ 0x994aa209, /* cps = 84.62, nrm = 8, interval = 4168.00 */
/* 053 */ 0x99829fe9, /* cps = 88.12, nrm = 8, interval = 4004.00 */
/* 054 */ 0x99be9fc1, /* cps = 91.88, nrm = 8, interval = 3844.00 */
/* 055 */ 0x99fc9f9a, /* cps = 95.75, nrm = 8, interval = 3688.00 */
/* 056 */ 0x9a3c9f75, /* cps = 99.75, nrm = 8, interval = 3540.00 */
/* 057 */ 0x9a809f51, /* cps = 104.00, nrm = 8, interval = 3396.00 */
/* 058 */ 0x9ac49f2f, /* cps = 108.25, nrm = 8, interval = 3260.00 */
/* 059 */ 0x9b0e9f0e, /* cps = 112.88, nrm = 8, interval = 3128.00 */
/* 060 */ 0x9b589eef, /* cps = 117.50, nrm = 8, interval = 3004.00 */
/* 061 */ 0x9ba69ed1, /* cps = 122.38, nrm = 8, interval = 2884.00 */
/* 062 */ 0x9bf89eb4, /* cps = 127.50, nrm = 8, interval = 2768.00 */
/* 063 */ 0x9c269e98, /* cps = 132.75, nrm = 8, interval = 2656.00 */
/* 064 */ 0x9c549e7d, /* cps = 138.50, nrm = 8, interval = 2548.00 */
/* 065 */ 0x9c849e63, /* cps = 144.50, nrm = 8, interval = 2444.00 */
/* 066 */ 0x9cb29e4b, /* cps = 150.25, nrm = 8, interval = 2348.00 */
/* 067 */ 0x9ce69e33, /* cps = 156.75, nrm = 8, interval = 2252.00 */
/* 068 */ 0x9d1cde1c, /* cps = 163.50, nrm = 16, interval = 2160.00 */
/* 069 */ 0x9d50de07, /* cps = 170.00, nrm = 16, interval = 2076.00 */
/* 070 */ 0x9d8adbe4, /* cps = 177.25, nrm = 16, interval = 1992.00 */
/* 071 */ 0x9dc4dbbc, /* cps = 184.50, nrm = 16, interval = 1912.00 */
/* 072 */ 0x9e02db96, /* cps = 192.25, nrm = 16, interval = 1836.00 */
/* 073 */ 0x9e42db71, /* cps = 200.25, nrm = 16, interval = 1762.00 */
/* 074 */ 0x9e86db4d, /* cps = 208.75, nrm = 16, interval = 1690.00 */
/* 075 */ 0x9ecedb2b, /* cps = 217.75, nrm = 16, interval = 1622.00 */
/* 076 */ 0x9f16db0a, /* cps = 226.75, nrm = 16, interval = 1556.00 */
/* 077 */ 0x9f62daeb, /* cps = 236.25, nrm = 16, interval = 1494.00 */
/* 078 */ 0x9fb2dacd, /* cps = 246.25, nrm = 16, interval = 1434.00 */
/* 079 */ 0xa002dab0, /* cps = 256.50, nrm = 16, interval = 1376.00 */
/* 080 */ 0xa02eda94, /* cps = 267.50, nrm = 16, interval = 1320.00 */
/* 081 */ 0xa05ada7a, /* cps = 278.50, nrm = 16, interval = 1268.00 */
/* 082 */ 0xa088da60, /* cps = 290.00, nrm = 16, interval = 1216.00 */
/* 083 */ 0xa0b8da48, /* cps = 302.00, nrm = 16, interval = 1168.00 */
/* 084 */ 0xa0ecda30, /* cps = 315.00, nrm = 16, interval = 1120.00 */
/* 085 */ 0xa1211a1a, /* cps = 328.00, nrm = 32, interval = 1076.00 */
/* 086 */ 0xa1591a04, /* cps = 342.00, nrm = 32, interval = 1032.00 */
/* 087 */ 0xa19117df, /* cps = 356.00, nrm = 32, interval = 991.00 */
/* 088 */ 0xa1cd17b7, /* cps = 371.00, nrm = 32, interval = 951.00 */
/* 089 */ 0xa20b1791, /* cps = 386.50, nrm = 32, interval = 913.00 */
/* 090 */ 0xa24d176c, /* cps = 403.00, nrm = 32, interval = 876.00 */
/* 091 */ 0xa28f1749, /* cps = 419.50, nrm = 32, interval = 841.00 */
/* 092 */ 0xa2d71727, /* cps = 437.50, nrm = 32, interval = 807.00 */
/* 093 */ 0xa31f1707, /* cps = 455.50, nrm = 32, interval = 775.00 */
/* 094 */ 0xa36d16e7, /* cps = 475.00, nrm = 32, interval = 743.00 */
/* 095 */ 0xa3bd16c9, /* cps = 495.00, nrm = 32, interval = 713.00 */
/* 096 */ 0xa40716ad, /* cps = 515.00, nrm = 32, interval = 685.00 */
/* 097 */ 0xa4331691, /* cps = 537.00, nrm = 32, interval = 657.00 */
/* 098 */ 0xa45f1677, /* cps = 559.00, nrm = 32, interval = 631.00 */
/* 099 */ 0xa48f165d, /* cps = 583.00, nrm = 32, interval = 605.00 */
/* 100 */ 0xa4bf1645, /* cps = 607.00, nrm = 32, interval = 581.00 */
/* 101 */ 0xa4f1162e, /* cps = 632.00, nrm = 32, interval = 558.00 */
/* 102 */ 0xa5291617, /* cps = 660.00, nrm = 32, interval = 535.00 */
/* 103 */ 0xa55f1602, /* cps = 687.00, nrm = 32, interval = 514.00 */
/* 104 */ 0xa59913da, /* cps = 716.00, nrm = 32, interval = 493.00 */
/* 105 */ 0xa5d513b2, /* cps = 746.00, nrm = 32, interval = 473.00 */
/* 106 */ 0xa613138c, /* cps = 777.00, nrm = 32, interval = 454.00 */
/* 107 */ 0xa6551368, /* cps = 810.00, nrm = 32, interval = 436.00 */
/* 108 */ 0xa6971345, /* cps = 843.00, nrm = 32, interval = 418.50 */
/* 109 */ 0xa6df1323, /* cps = 879.00, nrm = 32, interval = 401.50 */
/* 110 */ 0xa7291303, /* cps = 916.00, nrm = 32, interval = 385.50 */
/* 111 */ 0xa77512e4, /* cps = 954.00, nrm = 32, interval = 370.00 */
/* 112 */ 0xa7c512c6, /* cps = 994.00, nrm = 32, interval = 355.00 */
/* 113 */ 0xa80d12a9, /* cps = 1036.00, nrm = 32, interval = 340.50 */
/* 114 */ 0xa839128e, /* cps = 1080.00, nrm = 32, interval = 327.00 */
/* 115 */ 0xa8651274, /* cps = 1124.00, nrm = 32, interval = 314.00 */
/* 116 */ 0xa895125a, /* cps = 1172.00, nrm = 32, interval = 301.00 */
/* 117 */ 0xa8c71242, /* cps = 1222.00, nrm = 32, interval = 289.00 */
/* 118 */ 0xa8f9122b, /* cps = 1272.00, nrm = 32, interval = 277.50 */
/* 119 */ 0xa92f1214, /* cps = 1326.00, nrm = 32, interval = 266.00 */
/* 120 */ 0xa9670ffe, /* cps = 1382.00, nrm = 32, interval = 255.50 */
/* 121 */ 0xa9a10fd5, /* cps = 1440.00, nrm = 32, interval = 245.25 */
/* 122 */ 0xa9db0fae, /* cps = 1498.00, nrm = 32, interval = 235.50 */
/* 123 */ 0xaa1b0f88, /* cps = 1562.00, nrm = 32, interval = 226.00 */
/* 124 */ 0xaa5d0f63, /* cps = 1628.00, nrm = 32, interval = 216.75 */
/* 125 */ 0xaaa10f41, /* cps = 1696.00, nrm = 32, interval = 208.25 */
/* 126 */ 0xaae90f1f, /* cps = 1768.00, nrm = 32, interval = 199.75 */
/* 127 */ 0xab330eff, /* cps = 1842.00, nrm = 32, interval = 191.75 */
/* 128 */ 0xab7f0ee0, /* cps = 1918.00, nrm = 32, interval = 184.00 */
/* 129 */ 0xabd10ec2, /* cps = 2000.00, nrm = 32, interval = 176.50 */
/* 130 */ 0xac110ea6, /* cps = 2080.00, nrm = 32, interval = 169.50 */
/* 131 */ 0xac3d0e8b, /* cps = 2168.00, nrm = 32, interval = 162.75 */
/* 132 */ 0xac6d0e70, /* cps = 2264.00, nrm = 32, interval = 156.00 */
/* 133 */ 0xac9b0e57, /* cps = 2356.00, nrm = 32, interval = 149.75 */
/* 134 */ 0xaccd0e3f, /* cps = 2456.00, nrm = 32, interval = 143.75 */
/* 135 */ 0xacff0e28, /* cps = 2556.00, nrm = 32, interval = 138.00 */
/* 136 */ 0xad350e12, /* cps = 2664.00, nrm = 32, interval = 132.50 */
/* 137 */ 0xad6d0bf9, /* cps = 2776.00, nrm = 32, interval = 127.12 */
/* 138 */ 0xada70bd0, /* cps = 2892.00, nrm = 32, interval = 122.00 */
/* 139 */ 0xade30ba9, /* cps = 3012.00, nrm = 32, interval = 117.12 */
/* 140 */ 0xae230b83, /* cps = 3140.00, nrm = 32, interval = 112.38 */
/* 141 */ 0xae650b5f, /* cps = 3272.00, nrm = 32, interval = 107.88 */
/* 142 */ 0xaeab0b3c, /* cps = 3412.00, nrm = 32, interval = 103.50 */
/* 143 */ 0xaef10b1b, /* cps = 3552.00, nrm = 32, interval = 99.38 */
/* 144 */ 0xaf3b0afb, /* cps = 3700.00, nrm = 32, interval = 95.38 */
/* 145 */ 0xaf8b0adc, /* cps = 3860.00, nrm = 32, interval = 91.50 */
/* 146 */ 0xafd90abf, /* cps = 4016.00, nrm = 32, interval = 87.88 */
/* 147 */ 0xb0170aa3, /* cps = 4184.00, nrm = 32, interval = 84.38 */
/* 148 */ 0xb0430a87, /* cps = 4360.00, nrm = 32, interval = 80.88 */
/* 149 */ 0xb0710a6d, /* cps = 4544.00, nrm = 32, interval = 77.62 */
/* 150 */ 0xb0a10a54, /* cps = 4736.00, nrm = 32, interval = 74.50 */
/* 151 */ 0xb0d30a3c, /* cps = 4936.00, nrm = 32, interval = 71.50 */
/* 152 */ 0xb1070a25, /* cps = 5144.00, nrm = 32, interval = 68.62 */
/* 153 */ 0xb13d0a0f, /* cps = 5360.00, nrm = 32, interval = 65.88 */
/* 154 */ 0xb17507f4, /* cps = 5584.00, nrm = 32, interval = 63.25 */
/* 155 */ 0xb1af07cb, /* cps = 5816.00, nrm = 32, interval = 60.69 */
/* 156 */ 0xb1eb07a4, /* cps = 6056.00, nrm = 32, interval = 58.25 */
/* 157 */ 0xb22b077f, /* cps = 6312.00, nrm = 32, interval = 55.94 */
/* 158 */ 0xb26d075b, /* cps = 6576.00, nrm = 32, interval = 53.69 */
/* 159 */ 0xb2b30738, /* cps = 6856.00, nrm = 32, interval = 51.50 */
/* 160 */ 0xb2fb0717, /* cps = 7144.00, nrm = 32, interval = 49.44 */
/* 161 */ 0xb34506f7, /* cps = 7440.00, nrm = 32, interval = 47.44 */
/* 162 */ 0xb39306d9, /* cps = 7752.00, nrm = 32, interval = 45.56 */
/* 163 */ 0xb3e506bb, /* cps = 8080.00, nrm = 32, interval = 43.69 */
/* 164 */ 0xb41d069f, /* cps = 8416.00, nrm = 32, interval = 41.94 */
/* 165 */ 0xb4490684, /* cps = 8768.00, nrm = 32, interval = 40.25 */
/* 166 */ 0xb477066a, /* cps = 9136.00, nrm = 32, interval = 38.62 */
/* 167 */ 0xb4a70651, /* cps = 9520.00, nrm = 32, interval = 37.06 */
/* 168 */ 0xb4d90639, /* cps = 9920.00, nrm = 32, interval = 35.56 */
/* 169 */ 0xb50d0622, /* cps = 10336.00, nrm = 32, interval = 34.12 */
/* 170 */ 0xb545060c, /* cps = 10784.00, nrm = 32, interval = 32.75 */
/* 171 */ 0xb57b03ef, /* cps = 11216.00, nrm = 32, interval = 31.47 */
/* 172 */ 0xb5b503c7, /* cps = 11680.00, nrm = 32, interval = 30.22 */
/* 173 */ 0xb5f303a0, /* cps = 12176.00, nrm = 32, interval = 29.00 */
/* 174 */ 0xb633037a, /* cps = 12688.00, nrm = 32, interval = 27.81 */
/* 175 */ 0xb6750357, /* cps = 13216.00, nrm = 32, interval = 26.72 */
/* 176 */ 0xb6bb0334, /* cps = 13776.00, nrm = 32, interval = 25.62 */
/* 177 */ 0xb7030313, /* cps = 14352.00, nrm = 32, interval = 24.59 */
/* 178 */ 0xb74f02f3, /* cps = 14960.00, nrm = 32, interval = 23.59 */
/* 179 */ 0xb79d02d5, /* cps = 15584.00, nrm = 32, interval = 22.66 */
/* 180 */ 0xb7ed02b8, /* cps = 16224.00, nrm = 32, interval = 21.75 */
/* 181 */ 0xb821029c, /* cps = 16896.00, nrm = 32, interval = 20.88 */
/* 182 */ 0xb84f0281, /* cps = 17632.00, nrm = 32, interval = 20.03 */
/* 183 */ 0xb87d0267, /* cps = 18368.00, nrm = 32, interval = 19.22 */
/* 184 */ 0xb8ad024e, /* cps = 19136.00, nrm = 32, interval = 18.44 */
/* 185 */ 0xb8dd0237, /* cps = 19904.00, nrm = 32, interval = 17.72 */
/* 186 */ 0xb9130220, /* cps = 20768.00, nrm = 32, interval = 17.00 */
/* 187 */ 0xb949020a, /* cps = 21632.00, nrm = 32, interval = 16.31 */
/* 188 */ 0xb98301f5, /* cps = 22560.00, nrm = 32, interval = 15.66 */
/* 189 */ 0xb9bd01e1, /* cps = 23488.00, nrm = 32, interval = 15.03 */
/* 190 */ 0xb9fd01cd, /* cps = 24512.00, nrm = 32, interval = 14.41 */
/* 191 */ 0xba3b01bb, /* cps = 25504.00, nrm = 32, interval = 13.84 */
/* 192 */ 0xba7f01a9, /* cps = 26592.00, nrm = 32, interval = 13.28 */
/* 193 */ 0xbac30198, /* cps = 27680.00, nrm = 32, interval = 12.75 */
/* 194 */ 0xbb0f0187, /* cps = 28896.00, nrm = 32, interval = 12.22 */
/* 195 */ 0xbb570178, /* cps = 30048.00, nrm = 32, interval = 11.75 */
/* 196 */ 0xbbab0168, /* cps = 31392.00, nrm = 32, interval = 11.25 */
/* 197 */ 0xbbf9015a, /* cps = 32640.00, nrm = 32, interval = 10.81 */
/* 198 */ 0xbc27014c, /* cps = 33984.00, nrm = 32, interval = 10.38 */
/* 199 */ 0xbc53013f, /* cps = 35392.00, nrm = 32, interval = 9.97 */
/* 200 */ 0xbc830132, /* cps = 36928.00, nrm = 32, interval = 9.56 */
/* 201 */ 0xbcb50125, /* cps = 38528.00, nrm = 32, interval = 9.16 */
/* 202 */ 0xbce5011a, /* cps = 40064.00, nrm = 32, interval = 8.81 */
/* 203 */ 0xbd1d010e, /* cps = 41856.00, nrm = 32, interval = 8.44 */
/* 204 */ 0xbd530103, /* cps = 43584.00, nrm = 32, interval = 8.09 */
/* 205 */ 0xbd8b00f9, /* cps = 45376.00, nrm = 32, interval = 7.78 */
/* 206 */ 0xbdc500ef, /* cps = 47232.00, nrm = 32, interval = 7.47 */
/* 207 */ 0xbe0700e5, /* cps = 49344.00, nrm = 32, interval = 7.16 */
/* 208 */ 0xbe4500dc, /* cps = 51328.00, nrm = 32, interval = 6.88 */
/* 209 */ 0xbe8900d3, /* cps = 53504.00, nrm = 32, interval = 6.59 */
/* 210 */ 0xbecb00cb, /* cps = 55616.00, nrm = 32, interval = 6.34 */
/* 211 */ 0xbf1d00c2, /* cps = 58240.00, nrm = 32, interval = 6.06 */
/* 212 */ 0xbf6100bb, /* cps = 60416.00, nrm = 32, interval = 5.84 */
/* 213 */ 0xbfb500b3, /* cps = 63104.00, nrm = 32, interval = 5.59 */
/* 214 */ 0xc00300ac, /* cps = 65664.00, nrm = 32, interval = 5.38 */
/* 215 */ 0xc02f00a5, /* cps = 68480.00, nrm = 32, interval = 5.16 */
/* 216 */ 0xc05d009e, /* cps = 71424.00, nrm = 32, interval = 4.94 */
/* 217 */ 0xc0890098, /* cps = 74240.00, nrm = 32, interval = 4.75 */
/* 218 */ 0xc0b90092, /* cps = 77312.00, nrm = 32, interval = 4.56 */
/* 219 */ 0xc0ed008c, /* cps = 80640.00, nrm = 32, interval = 4.38 */
/* 220 */ 0xc1250086, /* cps = 84224.00, nrm = 32, interval = 4.19 */
/* 221 */ 0xc1590081, /* cps = 87552.00, nrm = 32, interval = 4.03 */
/* 222 */ 0xc191007c, /* cps = 91136.00, nrm = 32, interval = 3.88 */
/* 223 */ 0xc1cd0077, /* cps = 94976.00, nrm = 32, interval = 3.72 */
/* 224 */ 0xc20d0072, /* cps = 99072.00, nrm = 32, interval = 3.56 */
/* 225 */ 0xc255006d, /* cps = 103680.00, nrm = 32, interval = 3.41 */
/* 226 */ 0xc2910069, /* cps = 107520.00, nrm = 32, interval = 3.28 */
/* 227 */ 0xc2d50065, /* cps = 111872.00, nrm = 32, interval = 3.16 */
/* 228 */ 0xc32f0060, /* cps = 117632.00, nrm = 32, interval = 3.00 */
/* 229 */ 0xc36b005d, /* cps = 121472.00, nrm = 32, interval = 2.91 */
/* 230 */ 0xc3c10059, /* cps = 126976.00, nrm = 32, interval = 2.78 */
/* 231 */ 0xc40f0055, /* cps = 132864.00, nrm = 32, interval = 2.66 */
/* 232 */ 0xc4350052, /* cps = 137728.00, nrm = 32, interval = 2.56 */
/* 233 */ 0xc46d004e, /* cps = 144896.00, nrm = 32, interval = 2.44 */
/* 234 */ 0xc499004b, /* cps = 150528.00, nrm = 32, interval = 2.34 */
/* 235 */ 0xc4cb0048, /* cps = 156928.00, nrm = 32, interval = 2.25 */
/* 236 */ 0xc4ff0045, /* cps = 163584.00, nrm = 32, interval = 2.16 */
/* 237 */ 0xc5250043, /* cps = 168448.00, nrm = 32, interval = 2.09 */
/* 238 */ 0xc5630040, /* cps = 176384.00, nrm = 32, interval = 2.00 */
/* 239 */ 0xc5a7003d, /* cps = 185088.00, nrm = 32, interval = 1.91 */
/* 240 */ 0xc5d9003b, /* cps = 191488.00, nrm = 32, interval = 1.84 */
/* 241 */ 0xc6290038, /* cps = 201728.00, nrm = 32, interval = 1.75 */
/* 242 */ 0xc6630036, /* cps = 209152.00, nrm = 32, interval = 1.69 */
/* 243 */ 0xc6a30034, /* cps = 217344.00, nrm = 32, interval = 1.62 */
/* 244 */ 0xc6e70032, /* cps = 226048.00, nrm = 32, interval = 1.56 */
/* 245 */ 0xc72f0030, /* cps = 235264.00, nrm = 32, interval = 1.50 */
/* 246 */ 0xc77f002e, /* cps = 245504.00, nrm = 32, interval = 1.44 */
/* 247 */ 0xc7d7002c, /* cps = 256768.00, nrm = 32, interval = 1.38 */
/* 248 */ 0xc81b002a, /* cps = 268800.00, nrm = 32, interval = 1.31 */
/* 249 */ 0xc84f0028, /* cps = 282112.00, nrm = 32, interval = 1.25 */
/* 250 */ 0xc86d0027, /* cps = 289792.00, nrm = 32, interval = 1.22 */
/* 251 */ 0xc8a90025, /* cps = 305152.00, nrm = 32, interval = 1.16 */
/* 252 */ 0xc8cb0024, /* cps = 313856.00, nrm = 32, interval = 1.12 */
/* 253 */ 0xc9130022, /* cps = 332288.00, nrm = 32, interval = 1.06 */
/* 254 */ 0xc9390021, /* cps = 342016.00, nrm = 32, interval = 1.03 */
/* 255 */ 0xc9630020, /* cps = 352768.00, nrm = 32, interval = 1.00 */
};
static unsigned char rate_to_log[] =
{
/* 1.00 => 0 */ 0x00, /* => 10.02 */
/* 1.06 => 0 */ 0x00, /* => 10.02 */
/* 1.12 => 0 */ 0x00, /* => 10.02 */
/* 1.19 => 0 */ 0x00, /* => 10.02 */
/* 1.25 => 0 */ 0x00, /* => 10.02 */
/* 1.31 => 0 */ 0x00, /* => 10.02 */
/* 1.38 => 0 */ 0x00, /* => 10.02 */
/* 1.44 => 0 */ 0x00, /* => 10.02 */
/* 1.50 => 0 */ 0x00, /* => 10.02 */
/* 1.56 => 0 */ 0x00, /* => 10.02 */
/* 1.62 => 0 */ 0x00, /* => 10.02 */
/* 1.69 => 0 */ 0x00, /* => 10.02 */
/* 1.75 => 0 */ 0x00, /* => 10.02 */
/* 1.81 => 0 */ 0x00, /* => 10.02 */
/* 1.88 => 0 */ 0x00, /* => 10.02 */
/* 1.94 => 0 */ 0x00, /* => 10.02 */
/* 2.00 => 0 */ 0x00, /* => 10.02 */
/* 2.12 => 0 */ 0x00, /* => 10.02 */
/* 2.25 => 0 */ 0x00, /* => 10.02 */
/* 2.38 => 0 */ 0x00, /* => 10.02 */
/* 2.50 => 0 */ 0x00, /* => 10.02 */
/* 2.62 => 0 */ 0x00, /* => 10.02 */
/* 2.75 => 0 */ 0x00, /* => 10.02 */
/* 2.88 => 0 */ 0x00, /* => 10.02 */
/* 3.00 => 0 */ 0x00, /* => 10.02 */
/* 3.12 => 0 */ 0x00, /* => 10.02 */
/* 3.25 => 0 */ 0x00, /* => 10.02 */
/* 3.38 => 0 */ 0x00, /* => 10.02 */
/* 3.50 => 0 */ 0x00, /* => 10.02 */
/* 3.62 => 0 */ 0x00, /* => 10.02 */
/* 3.75 => 0 */ 0x00, /* => 10.02 */
/* 3.88 => 0 */ 0x00, /* => 10.02 */
/* 4.00 => 0 */ 0x00, /* => 10.02 */
/* 4.25 => 0 */ 0x00, /* => 10.02 */
/* 4.50 => 0 */ 0x00, /* => 10.02 */
/* 4.75 => 0 */ 0x00, /* => 10.02 */
/* 5.00 => 0 */ 0x00, /* => 10.02 */
/* 5.25 => 0 */ 0x00, /* => 10.02 */
/* 5.50 => 0 */ 0x00, /* => 10.02 */
/* 5.75 => 0 */ 0x00, /* => 10.02 */
/* 6.00 => 0 */ 0x00, /* => 10.02 */
/* 6.25 => 0 */ 0x00, /* => 10.02 */
/* 6.50 => 0 */ 0x00, /* => 10.02 */
/* 6.75 => 0 */ 0x00, /* => 10.02 */
/* 7.00 => 0 */ 0x00, /* => 10.02 */
/* 7.25 => 0 */ 0x00, /* => 10.02 */
/* 7.50 => 0 */ 0x00, /* => 10.02 */
/* 7.75 => 0 */ 0x00, /* => 10.02 */
/* 8.00 => 0 */ 0x00, /* => 10.02 */
/* 8.50 => 0 */ 0x00, /* => 10.02 */
/* 9.00 => 0 */ 0x00, /* => 10.02 */
/* 9.50 => 0 */ 0x00, /* => 10.02 */
/* 10.00 => 0 */ 0x00, /* => 10.02 */
/* 10.50 => 1 */ 0x01, /* => 10.42 */
/* 11.00 => 2 */ 0x02, /* => 10.86 */
/* 11.50 => 3 */ 0x03, /* => 11.31 */
/* 12.00 => 4 */ 0x04, /* => 11.78 */
/* 12.50 => 5 */ 0x05, /* => 12.28 */
/* 13.00 => 6 */ 0x06, /* => 12.80 */
/* 13.50 => 7 */ 0x07, /* => 13.33 */
/* 14.00 => 8 */ 0x08, /* => 13.89 */
/* 14.50 => 9 */ 0x09, /* => 14.48 */
/* 15.00 => 9 */ 0x09, /* => 14.48 */
/* 15.50 => 10 */ 0x0a, /* => 15.08 */
/* 16.00 => 11 */ 0x0b, /* => 15.72 */
/* 17.00 => 12 */ 0x0c, /* => 16.38 */
/* 18.00 => 14 */ 0x0e, /* => 17.75 */
/* 19.00 => 15 */ 0x0f, /* => 18.50 */
/* 20.00 => 16 */ 0x10, /* => 19.28 */
/* 21.00 => 18 */ 0x12, /* => 20.94 */
/* 22.00 => 19 */ 0x13, /* => 21.81 */
/* 23.00 => 20 */ 0x14, /* => 22.75 */
/* 24.00 => 21 */ 0x15, /* => 23.69 */
/* 25.00 => 22 */ 0x16, /* => 24.69 */
/* 26.00 => 23 */ 0x17, /* => 25.72 */
/* 27.00 => 24 */ 0x18, /* => 26.81 */
/* 28.00 => 25 */ 0x19, /* => 27.94 */
/* 29.00 => 25 */ 0x19, /* => 27.94 */
/* 30.00 => 26 */ 0x1a, /* => 29.09 */
/* 31.00 => 27 */ 0x1b, /* => 30.31 */
/* 32.00 => 28 */ 0x1c, /* => 31.56 */
/* 34.00 => 29 */ 0x1d, /* => 32.94 */
/* 36.00 => 31 */ 0x1f, /* => 35.69 */
/* 38.00 => 32 */ 0x20, /* => 37.19 */
/* 40.00 => 33 */ 0x21, /* => 38.75 */
/* 42.00 => 34 */ 0x22, /* => 40.38 */
/* 44.00 => 36 */ 0x24, /* => 43.88 */
/* 46.00 => 37 */ 0x25, /* => 45.69 */
/* 48.00 => 38 */ 0x26, /* => 47.62 */
/* 50.00 => 39 */ 0x27, /* => 49.62 */
/* 52.00 => 40 */ 0x28, /* => 51.69 */
/* 54.00 => 41 */ 0x29, /* => 53.88 */
/* 56.00 => 41 */ 0x29, /* => 53.88 */
/* 58.00 => 42 */ 0x2a, /* => 56.12 */
/* 60.00 => 43 */ 0x2b, /* => 58.44 */
/* 62.00 => 44 */ 0x2c, /* => 60.94 */
/* 64.00 => 45 */ 0x2d, /* => 63.50 */
/* 68.00 => 46 */ 0x2e, /* => 66.12 */
/* 72.00 => 48 */ 0x30, /* => 71.88 */
/* 76.00 => 49 */ 0x31, /* => 74.75 */
/* 80.00 => 50 */ 0x32, /* => 78.00 */
/* 84.00 => 51 */ 0x33, /* => 81.25 */
/* 88.00 => 52 */ 0x34, /* => 84.62 */
/* 92.00 => 54 */ 0x36, /* => 91.88 */
/* 96.00 => 55 */ 0x37, /* => 95.75 */
/* 100.00 => 56 */ 0x38, /* => 99.75 */
/* 104.00 => 56 */ 0x38, /* => 99.75 */
/* 108.00 => 57 */ 0x39, /* => 104.00 */
/* 112.00 => 58 */ 0x3a, /* => 108.25 */
/* 116.00 => 59 */ 0x3b, /* => 112.88 */
/* 120.00 => 60 */ 0x3c, /* => 117.50 */
/* 124.00 => 61 */ 0x3d, /* => 122.38 */
/* 128.00 => 62 */ 0x3e, /* => 127.50 */
/* 136.00 => 63 */ 0x3f, /* => 132.75 */
/* 144.00 => 64 */ 0x40, /* => 138.50 */
/* 152.00 => 66 */ 0x42, /* => 150.25 */
/* 160.00 => 67 */ 0x43, /* => 156.75 */
/* 168.00 => 68 */ 0x44, /* => 163.50 */
/* 176.00 => 69 */ 0x45, /* => 170.00 */
/* 184.00 => 70 */ 0x46, /* => 177.25 */
/* 192.00 => 71 */ 0x47, /* => 184.50 */
/* 200.00 => 72 */ 0x48, /* => 192.25 */
/* 208.00 => 73 */ 0x49, /* => 200.25 */
/* 216.00 => 74 */ 0x4a, /* => 208.75 */
/* 224.00 => 75 */ 0x4b, /* => 217.75 */
/* 232.00 => 76 */ 0x4c, /* => 226.75 */
/* 240.00 => 77 */ 0x4d, /* => 236.25 */
/* 248.00 => 78 */ 0x4e, /* => 246.25 */
/* 256.00 => 78 */ 0x4e, /* => 246.25 */
/* 272.00 => 80 */ 0x50, /* => 267.50 */
/* 288.00 => 81 */ 0x51, /* => 278.50 */
/* 304.00 => 83 */ 0x53, /* => 302.00 */
/* 320.00 => 84 */ 0x54, /* => 315.00 */
/* 336.00 => 85 */ 0x55, /* => 328.00 */
/* 352.00 => 86 */ 0x56, /* => 342.00 */
/* 368.00 => 87 */ 0x57, /* => 356.00 */
/* 384.00 => 88 */ 0x58, /* => 371.00 */
/* 400.00 => 89 */ 0x59, /* => 386.50 */
/* 416.00 => 90 */ 0x5a, /* => 403.00 */
/* 432.00 => 91 */ 0x5b, /* => 419.50 */
/* 448.00 => 92 */ 0x5c, /* => 437.50 */
/* 464.00 => 93 */ 0x5d, /* => 455.50 */
/* 480.00 => 94 */ 0x5e, /* => 475.00 */
/* 496.00 => 95 */ 0x5f, /* => 495.00 */
/* 512.00 => 95 */ 0x5f, /* => 495.00 */
/* 544.00 => 97 */ 0x61, /* => 537.00 */
/* 576.00 => 98 */ 0x62, /* => 559.00 */
/* 608.00 => 100 */ 0x64, /* => 607.00 */
/* 640.00 => 101 */ 0x65, /* => 632.00 */
/* 672.00 => 102 */ 0x66, /* => 660.00 */
/* 704.00 => 103 */ 0x67, /* => 687.00 */
/* 736.00 => 104 */ 0x68, /* => 716.00 */
/* 768.00 => 105 */ 0x69, /* => 746.00 */
/* 800.00 => 106 */ 0x6a, /* => 777.00 */
/* 832.00 => 107 */ 0x6b, /* => 810.00 */
/* 864.00 => 108 */ 0x6c, /* => 843.00 */
/* 896.00 => 109 */ 0x6d, /* => 879.00 */
/* 928.00 => 110 */ 0x6e, /* => 916.00 */
/* 960.00 => 111 */ 0x6f, /* => 954.00 */
/* 992.00 => 111 */ 0x6f, /* => 954.00 */
/* 1024.00 => 112 */ 0x70, /* => 994.00 */
/* 1088.00 => 114 */ 0x72, /* => 1080.00 */
/* 1152.00 => 115 */ 0x73, /* => 1124.00 */
/* 1216.00 => 116 */ 0x74, /* => 1172.00 */
/* 1280.00 => 118 */ 0x76, /* => 1272.00 */
/* 1344.00 => 119 */ 0x77, /* => 1326.00 */
/* 1408.00 => 120 */ 0x78, /* => 1382.00 */
/* 1472.00 => 121 */ 0x79, /* => 1440.00 */
/* 1536.00 => 122 */ 0x7a, /* => 1498.00 */
/* 1600.00 => 123 */ 0x7b, /* => 1562.00 */
/* 1664.00 => 124 */ 0x7c, /* => 1628.00 */
/* 1728.00 => 125 */ 0x7d, /* => 1696.00 */
/* 1792.00 => 126 */ 0x7e, /* => 1768.00 */
/* 1856.00 => 127 */ 0x7f, /* => 1842.00 */
/* 1920.00 => 128 */ 0x80, /* => 1918.00 */
/* 1984.00 => 128 */ 0x80, /* => 1918.00 */
/* 2048.00 => 129 */ 0x81, /* => 2000.00 */
/* 2176.00 => 131 */ 0x83, /* => 2168.00 */
/* 2304.00 => 132 */ 0x84, /* => 2264.00 */
/* 2432.00 => 133 */ 0x85, /* => 2356.00 */
/* 2560.00 => 135 */ 0x87, /* => 2556.00 */
/* 2688.00 => 136 */ 0x88, /* => 2664.00 */
/* 2816.00 => 137 */ 0x89, /* => 2776.00 */
/* 2944.00 => 138 */ 0x8a, /* => 2892.00 */
/* 3072.00 => 139 */ 0x8b, /* => 3012.00 */
/* 3200.00 => 140 */ 0x8c, /* => 3140.00 */
/* 3328.00 => 141 */ 0x8d, /* => 3272.00 */
/* 3456.00 => 142 */ 0x8e, /* => 3412.00 */
/* 3584.00 => 143 */ 0x8f, /* => 3552.00 */
/* 3712.00 => 144 */ 0x90, /* => 3700.00 */
/* 3840.00 => 144 */ 0x90, /* => 3700.00 */
/* 3968.00 => 145 */ 0x91, /* => 3860.00 */
/* 4096.00 => 146 */ 0x92, /* => 4016.00 */
/* 4352.00 => 147 */ 0x93, /* => 4184.00 */
/* 4608.00 => 149 */ 0x95, /* => 4544.00 */
/* 4864.00 => 150 */ 0x96, /* => 4736.00 */
/* 5120.00 => 151 */ 0x97, /* => 4936.00 */
/* 5376.00 => 153 */ 0x99, /* => 5360.00 */
/* 5632.00 => 154 */ 0x9a, /* => 5584.00 */
/* 5888.00 => 155 */ 0x9b, /* => 5816.00 */
/* 6144.00 => 156 */ 0x9c, /* => 6056.00 */
/* 6400.00 => 157 */ 0x9d, /* => 6312.00 */
/* 6656.00 => 158 */ 0x9e, /* => 6576.00 */
/* 6912.00 => 159 */ 0x9f, /* => 6856.00 */
/* 7168.00 => 160 */ 0xa0, /* => 7144.00 */
/* 7424.00 => 160 */ 0xa0, /* => 7144.00 */
/* 7680.00 => 161 */ 0xa1, /* => 7440.00 */
/* 7936.00 => 162 */ 0xa2, /* => 7752.00 */
/* 8192.00 => 163 */ 0xa3, /* => 8080.00 */
/* 8704.00 => 164 */ 0xa4, /* => 8416.00 */
/* 9216.00 => 166 */ 0xa6, /* => 9136.00 */
/* 9728.00 => 167 */ 0xa7, /* => 9520.00 */
/* 10240.00 => 168 */ 0xa8, /* => 9920.00 */
/* 10752.00 => 169 */ 0xa9, /* => 10336.00 */
/* 11264.00 => 171 */ 0xab, /* => 11216.00 */
/* 11776.00 => 172 */ 0xac, /* => 11680.00 */
/* 12288.00 => 173 */ 0xad, /* => 12176.00 */
/* 12800.00 => 174 */ 0xae, /* => 12688.00 */
/* 13312.00 => 175 */ 0xaf, /* => 13216.00 */
/* 13824.00 => 176 */ 0xb0, /* => 13776.00 */
/* 14336.00 => 176 */ 0xb0, /* => 13776.00 */
/* 14848.00 => 177 */ 0xb1, /* => 14352.00 */
/* 15360.00 => 178 */ 0xb2, /* => 14960.00 */
/* 15872.00 => 179 */ 0xb3, /* => 15584.00 */
/* 16384.00 => 180 */ 0xb4, /* => 16224.00 */
/* 17408.00 => 181 */ 0xb5, /* => 16896.00 */
/* 18432.00 => 183 */ 0xb7, /* => 18368.00 */
/* 19456.00 => 184 */ 0xb8, /* => 19136.00 */
/* 20480.00 => 185 */ 0xb9, /* => 19904.00 */
/* 21504.00 => 186 */ 0xba, /* => 20768.00 */
/* 22528.00 => 187 */ 0xbb, /* => 21632.00 */
/* 23552.00 => 189 */ 0xbd, /* => 23488.00 */
/* 24576.00 => 190 */ 0xbe, /* => 24512.00 */
/* 25600.00 => 191 */ 0xbf, /* => 25504.00 */
/* 26624.00 => 192 */ 0xc0, /* => 26592.00 */
/* 27648.00 => 192 */ 0xc0, /* => 26592.00 */
/* 28672.00 => 193 */ 0xc1, /* => 27680.00 */
/* 29696.00 => 194 */ 0xc2, /* => 28896.00 */
/* 30720.00 => 195 */ 0xc3, /* => 30048.00 */
/* 31744.00 => 196 */ 0xc4, /* => 31392.00 */
/* 32768.00 => 197 */ 0xc5, /* => 32640.00 */
/* 34816.00 => 198 */ 0xc6, /* => 33984.00 */
/* 36864.00 => 199 */ 0xc7, /* => 35392.00 */
/* 38912.00 => 201 */ 0xc9, /* => 38528.00 */
/* 40960.00 => 202 */ 0xca, /* => 40064.00 */
/* 43008.00 => 203 */ 0xcb, /* => 41856.00 */
/* 45056.00 => 204 */ 0xcc, /* => 43584.00 */
/* 47104.00 => 205 */ 0xcd, /* => 45376.00 */
/* 49152.00 => 206 */ 0xce, /* => 47232.00 */
/* 51200.00 => 207 */ 0xcf, /* => 49344.00 */
/* 53248.00 => 208 */ 0xd0, /* => 51328.00 */
/* 55296.00 => 209 */ 0xd1, /* => 53504.00 */
/* 57344.00 => 210 */ 0xd2, /* => 55616.00 */
/* 59392.00 => 211 */ 0xd3, /* => 58240.00 */
/* 61440.00 => 212 */ 0xd4, /* => 60416.00 */
/* 63488.00 => 213 */ 0xd5, /* => 63104.00 */
/* 65536.00 => 213 */ 0xd5, /* => 63104.00 */
/* 69632.00 => 215 */ 0xd7, /* => 68480.00 */
/* 73728.00 => 216 */ 0xd8, /* => 71424.00 */
/* 77824.00 => 218 */ 0xda, /* => 77312.00 */
/* 81920.00 => 219 */ 0xdb, /* => 80640.00 */
/* 86016.00 => 220 */ 0xdc, /* => 84224.00 */
/* 90112.00 => 221 */ 0xdd, /* => 87552.00 */
/* 94208.00 => 222 */ 0xde, /* => 91136.00 */
/* 98304.00 => 223 */ 0xdf, /* => 94976.00 */
/* 102400.00 => 224 */ 0xe0, /* => 99072.00 */
/* 106496.00 => 225 */ 0xe1, /* => 103680.00 */
/* 110592.00 => 226 */ 0xe2, /* => 107520.00 */
/* 114688.00 => 227 */ 0xe3, /* => 111872.00 */
/* 118784.00 => 228 */ 0xe4, /* => 117632.00 */
/* 122880.00 => 229 */ 0xe5, /* => 121472.00 */
/* 126976.00 => 229 */ 0xe5, /* => 121472.00 */
/* 131072.00 => 230 */ 0xe6, /* => 126976.00 */
/* 139264.00 => 232 */ 0xe8, /* => 137728.00 */
/* 147456.00 => 233 */ 0xe9, /* => 144896.00 */
/* 155648.00 => 234 */ 0xea, /* => 150528.00 */
/* 163840.00 => 236 */ 0xec, /* => 163584.00 */
/* 172032.00 => 237 */ 0xed, /* => 168448.00 */
/* 180224.00 => 238 */ 0xee, /* => 176384.00 */
/* 188416.00 => 239 */ 0xef, /* => 185088.00 */
/* 196608.00 => 240 */ 0xf0, /* => 191488.00 */
/* 204800.00 => 241 */ 0xf1, /* => 201728.00 */
/* 212992.00 => 242 */ 0xf2, /* => 209152.00 */
/* 221184.00 => 243 */ 0xf3, /* => 217344.00 */
/* 229376.00 => 244 */ 0xf4, /* => 226048.00 */
/* 237568.00 => 245 */ 0xf5, /* => 235264.00 */
/* 245760.00 => 246 */ 0xf6, /* => 245504.00 */
/* 253952.00 => 246 */ 0xf6, /* => 245504.00 */
/* 262144.00 => 247 */ 0xf7, /* => 256768.00 */
/* 278528.00 => 248 */ 0xf8, /* => 268800.00 */
/* 294912.00 => 250 */ 0xfa, /* => 289792.00 */
/* 311296.00 => 251 */ 0xfb, /* => 305152.00 */
/* 327680.00 => 252 */ 0xfc, /* => 313856.00 */
/* 344064.00 => 254 */ 0xfe, /* => 342016.00 */
/* 360448.00 => 255 */ 0xff, /* => 352768.00 */
/* 376832.00 => 255 */ 0xff, /* => 352768.00 */
/* 393216.00 => 255 */ 0xff, /* => 352768.00 */
/* 409600.00 => 255 */ 0xff, /* => 352768.00 */
/* 425984.00 => 255 */ 0xff, /* => 352768.00 */
/* 442368.00 => 255 */ 0xff, /* => 352768.00 */
/* 458752.00 => 255 */ 0xff, /* => 352768.00 */
/* 475136.00 => 255 */ 0xff, /* => 352768.00 */
/* 491520.00 => 255 */ 0xff, /* => 352768.00 */
/* 507904.00 => 255 */ 0xff, /* => 352768.00 */
/* 524288.00 => 255 */ 0xff, /* => 352768.00 */
/* 557056.00 => 255 */ 0xff, /* => 352768.00 */
/* 589824.00 => 255 */ 0xff, /* => 352768.00 */
/* 622592.00 => 255 */ 0xff, /* => 352768.00 */
/* 655360.00 => 255 */ 0xff, /* => 352768.00 */
/* 688128.00 => 255 */ 0xff, /* => 352768.00 */
/* 720896.00 => 255 */ 0xff, /* => 352768.00 */
/* 753664.00 => 255 */ 0xff, /* => 352768.00 */
/* 786432.00 => 255 */ 0xff, /* => 352768.00 */
/* 819200.00 => 255 */ 0xff, /* => 352768.00 */
/* 851968.00 => 255 */ 0xff, /* => 352768.00 */
/* 884736.00 => 255 */ 0xff, /* => 352768.00 */
/* 917504.00 => 255 */ 0xff, /* => 352768.00 */
/* 950272.00 => 255 */ 0xff, /* => 352768.00 */
/* 983040.00 => 255 */ 0xff, /* => 352768.00 */
/* 1015808.00 => 255 */ 0xff, /* => 352768.00 */
/* 1048576.00 => 255 */ 0xff, /* => 352768.00 */
/* 1114112.00 => 255 */ 0xff, /* => 352768.00 */
/* 1179648.00 => 255 */ 0xff, /* => 352768.00 */
/* 1245184.00 => 255 */ 0xff, /* => 352768.00 */
/* 1310720.00 => 255 */ 0xff, /* => 352768.00 */
/* 1376256.00 => 255 */ 0xff, /* => 352768.00 */
/* 1441792.00 => 255 */ 0xff, /* => 352768.00 */
/* 1507328.00 => 255 */ 0xff, /* => 352768.00 */
/* 1572864.00 => 255 */ 0xff, /* => 352768.00 */
/* 1638400.00 => 255 */ 0xff, /* => 352768.00 */
/* 1703936.00 => 255 */ 0xff, /* => 352768.00 */
/* 1769472.00 => 255 */ 0xff, /* => 352768.00 */
/* 1835008.00 => 255 */ 0xff, /* => 352768.00 */
/* 1900544.00 => 255 */ 0xff, /* => 352768.00 */
/* 1966080.00 => 255 */ 0xff, /* => 352768.00 */
/* 2031616.00 => 255 */ 0xff, /* => 352768.00 */
/* 2097152.00 => 255 */ 0xff, /* => 352768.00 */
/* 2228224.00 => 255 */ 0xff, /* => 352768.00 */
/* 2359296.00 => 255 */ 0xff, /* => 352768.00 */
/* 2490368.00 => 255 */ 0xff, /* => 352768.00 */
/* 2621440.00 => 255 */ 0xff, /* => 352768.00 */
/* 2752512.00 => 255 */ 0xff, /* => 352768.00 */
/* 2883584.00 => 255 */ 0xff, /* => 352768.00 */
/* 3014656.00 => 255 */ 0xff, /* => 352768.00 */
/* 3145728.00 => 255 */ 0xff, /* => 352768.00 */
/* 3276800.00 => 255 */ 0xff, /* => 352768.00 */
/* 3407872.00 => 255 */ 0xff, /* => 352768.00 */
/* 3538944.00 => 255 */ 0xff, /* => 352768.00 */
/* 3670016.00 => 255 */ 0xff, /* => 352768.00 */
/* 3801088.00 => 255 */ 0xff, /* => 352768.00 */
/* 3932160.00 => 255 */ 0xff, /* => 352768.00 */
/* 4063232.00 => 255 */ 0xff, /* => 352768.00 */
/* 4194304.00 => 255 */ 0xff, /* => 352768.00 */
/* 4456448.00 => 255 */ 0xff, /* => 352768.00 */
/* 4718592.00 => 255 */ 0xff, /* => 352768.00 */
/* 4980736.00 => 255 */ 0xff, /* => 352768.00 */
/* 5242880.00 => 255 */ 0xff, /* => 352768.00 */
/* 5505024.00 => 255 */ 0xff, /* => 352768.00 */
/* 5767168.00 => 255 */ 0xff, /* => 352768.00 */
/* 6029312.00 => 255 */ 0xff, /* => 352768.00 */
/* 6291456.00 => 255 */ 0xff, /* => 352768.00 */
/* 6553600.00 => 255 */ 0xff, /* => 352768.00 */
/* 6815744.00 => 255 */ 0xff, /* => 352768.00 */
/* 7077888.00 => 255 */ 0xff, /* => 352768.00 */
/* 7340032.00 => 255 */ 0xff, /* => 352768.00 */
/* 7602176.00 => 255 */ 0xff, /* => 352768.00 */
/* 7864320.00 => 255 */ 0xff, /* => 352768.00 */
/* 8126464.00 => 255 */ 0xff, /* => 352768.00 */
/* 8388608.00 => 255 */ 0xff, /* => 352768.00 */
/* 8912896.00 => 255 */ 0xff, /* => 352768.00 */
/* 9437184.00 => 255 */ 0xff, /* => 352768.00 */
/* 9961472.00 => 255 */ 0xff, /* => 352768.00 */
/* 10485760.00 => 255 */ 0xff, /* => 352768.00 */
/* 11010048.00 => 255 */ 0xff, /* => 352768.00 */
/* 11534336.00 => 255 */ 0xff, /* => 352768.00 */
/* 12058624.00 => 255 */ 0xff, /* => 352768.00 */
/* 12582912.00 => 255 */ 0xff, /* => 352768.00 */
/* 13107200.00 => 255 */ 0xff, /* => 352768.00 */
/* 13631488.00 => 255 */ 0xff, /* => 352768.00 */
/* 14155776.00 => 255 */ 0xff, /* => 352768.00 */
/* 14680064.00 => 255 */ 0xff, /* => 352768.00 */
/* 15204352.00 => 255 */ 0xff, /* => 352768.00 */
/* 15728640.00 => 255 */ 0xff, /* => 352768.00 */
/* 16252928.00 => 255 */ 0xff, /* => 352768.00 */
/* 16777216.00 => 255 */ 0xff, /* => 352768.00 */
/* 17825792.00 => 255 */ 0xff, /* => 352768.00 */
/* 18874368.00 => 255 */ 0xff, /* => 352768.00 */
/* 19922944.00 => 255 */ 0xff, /* => 352768.00 */
/* 20971520.00 => 255 */ 0xff, /* => 352768.00 */
/* 22020096.00 => 255 */ 0xff, /* => 352768.00 */
/* 23068672.00 => 255 */ 0xff, /* => 352768.00 */
/* 24117248.00 => 255 */ 0xff, /* => 352768.00 */
/* 25165824.00 => 255 */ 0xff, /* => 352768.00 */
/* 26214400.00 => 255 */ 0xff, /* => 352768.00 */
/* 27262976.00 => 255 */ 0xff, /* => 352768.00 */
/* 28311552.00 => 255 */ 0xff, /* => 352768.00 */
/* 29360128.00 => 255 */ 0xff, /* => 352768.00 */
/* 30408704.00 => 255 */ 0xff, /* => 352768.00 */
/* 31457280.00 => 255 */ 0xff, /* => 352768.00 */
/* 32505856.00 => 255 */ 0xff, /* => 352768.00 */
/* 33554432.00 => 255 */ 0xff, /* => 352768.00 */
/* 35651584.00 => 255 */ 0xff, /* => 352768.00 */
/* 37748736.00 => 255 */ 0xff, /* => 352768.00 */
/* 39845888.00 => 255 */ 0xff, /* => 352768.00 */
/* 41943040.00 => 255 */ 0xff, /* => 352768.00 */
/* 44040192.00 => 255 */ 0xff, /* => 352768.00 */
/* 46137344.00 => 255 */ 0xff, /* => 352768.00 */
/* 48234496.00 => 255 */ 0xff, /* => 352768.00 */
/* 50331648.00 => 255 */ 0xff, /* => 352768.00 */
/* 52428800.00 => 255 */ 0xff, /* => 352768.00 */
/* 54525952.00 => 255 */ 0xff, /* => 352768.00 */
/* 56623104.00 => 255 */ 0xff, /* => 352768.00 */
/* 58720256.00 => 255 */ 0xff, /* => 352768.00 */
/* 60817408.00 => 255 */ 0xff, /* => 352768.00 */
/* 62914560.00 => 255 */ 0xff, /* => 352768.00 */
/* 65011712.00 => 255 */ 0xff, /* => 352768.00 */
/* 67108864.00 => 255 */ 0xff, /* => 352768.00 */
/* 71303168.00 => 255 */ 0xff, /* => 352768.00 */
/* 75497472.00 => 255 */ 0xff, /* => 352768.00 */
/* 79691776.00 => 255 */ 0xff, /* => 352768.00 */
/* 83886080.00 => 255 */ 0xff, /* => 352768.00 */
/* 88080384.00 => 255 */ 0xff, /* => 352768.00 */
/* 92274688.00 => 255 */ 0xff, /* => 352768.00 */
/* 96468992.00 => 255 */ 0xff, /* => 352768.00 */
/* 100663296.00 => 255 */ 0xff, /* => 352768.00 */
/* 104857600.00 => 255 */ 0xff, /* => 352768.00 */
/* 109051904.00 => 255 */ 0xff, /* => 352768.00 */
/* 113246208.00 => 255 */ 0xff, /* => 352768.00 */
/* 117440512.00 => 255 */ 0xff, /* => 352768.00 */
/* 121634816.00 => 255 */ 0xff, /* => 352768.00 */
/* 125829120.00 => 255 */ 0xff, /* => 352768.00 */
/* 130023424.00 => 255 */ 0xff, /* => 352768.00 */
/* 134217728.00 => 255 */ 0xff, /* => 352768.00 */
/* 142606336.00 => 255 */ 0xff, /* => 352768.00 */
/* 150994944.00 => 255 */ 0xff, /* => 352768.00 */
/* 159383552.00 => 255 */ 0xff, /* => 352768.00 */
/* 167772160.00 => 255 */ 0xff, /* => 352768.00 */
/* 176160768.00 => 255 */ 0xff, /* => 352768.00 */
/* 184549376.00 => 255 */ 0xff, /* => 352768.00 */
/* 192937984.00 => 255 */ 0xff, /* => 352768.00 */
/* 201326592.00 => 255 */ 0xff, /* => 352768.00 */
/* 209715200.00 => 255 */ 0xff, /* => 352768.00 */
/* 218103808.00 => 255 */ 0xff, /* => 352768.00 */
/* 226492416.00 => 255 */ 0xff, /* => 352768.00 */
/* 234881024.00 => 255 */ 0xff, /* => 352768.00 */
/* 243269632.00 => 255 */ 0xff, /* => 352768.00 */
/* 251658240.00 => 255 */ 0xff, /* => 352768.00 */
/* 260046848.00 => 255 */ 0xff, /* => 352768.00 */
/* 268435456.00 => 255 */ 0xff, /* => 352768.00 */
/* 285212672.00 => 255 */ 0xff, /* => 352768.00 */
/* 301989888.00 => 255 */ 0xff, /* => 352768.00 */
/* 318767104.00 => 255 */ 0xff, /* => 352768.00 */
/* 335544320.00 => 255 */ 0xff, /* => 352768.00 */
/* 352321536.00 => 255 */ 0xff, /* => 352768.00 */
/* 369098752.00 => 255 */ 0xff, /* => 352768.00 */
/* 385875968.00 => 255 */ 0xff, /* => 352768.00 */
/* 402653184.00 => 255 */ 0xff, /* => 352768.00 */
/* 419430400.00 => 255 */ 0xff, /* => 352768.00 */
/* 436207616.00 => 255 */ 0xff, /* => 352768.00 */
/* 452984832.00 => 255 */ 0xff, /* => 352768.00 */
/* 469762048.00 => 255 */ 0xff, /* => 352768.00 */
/* 486539264.00 => 255 */ 0xff, /* => 352768.00 */
/* 503316480.00 => 255 */ 0xff, /* => 352768.00 */
/* 520093696.00 => 255 */ 0xff, /* => 352768.00 */
/* 536870912.00 => 255 */ 0xff, /* => 352768.00 */
/* 570425344.00 => 255 */ 0xff, /* => 352768.00 */
/* 603979776.00 => 255 */ 0xff, /* => 352768.00 */
/* 637534208.00 => 255 */ 0xff, /* => 352768.00 */
/* 671088640.00 => 255 */ 0xff, /* => 352768.00 */
/* 704643072.00 => 255 */ 0xff, /* => 352768.00 */
/* 738197504.00 => 255 */ 0xff, /* => 352768.00 */
/* 771751936.00 => 255 */ 0xff, /* => 352768.00 */
/* 805306368.00 => 255 */ 0xff, /* => 352768.00 */
/* 838860800.00 => 255 */ 0xff, /* => 352768.00 */
/* 872415232.00 => 255 */ 0xff, /* => 352768.00 */
/* 905969664.00 => 255 */ 0xff, /* => 352768.00 */
/* 939524096.00 => 255 */ 0xff, /* => 352768.00 */
/* 973078528.00 => 255 */ 0xff, /* => 352768.00 */
/* 1006632960.00 => 255 */ 0xff, /* => 352768.00 */
/* 1040187392.00 => 255 */ 0xff, /* => 352768.00 */
/* 1073741824.00 => 255 */ 0xff, /* => 352768.00 */
/* 1140850688.00 => 255 */ 0xff, /* => 352768.00 */
/* 1207959552.00 => 255 */ 0xff, /* => 352768.00 */
/* 1275068416.00 => 255 */ 0xff, /* => 352768.00 */
/* 1342177280.00 => 255 */ 0xff, /* => 352768.00 */
/* 1409286144.00 => 255 */ 0xff, /* => 352768.00 */
/* 1476395008.00 => 255 */ 0xff, /* => 352768.00 */
/* 1543503872.00 => 255 */ 0xff, /* => 352768.00 */
/* 1610612736.00 => 255 */ 0xff, /* => 352768.00 */
/* 1677721600.00 => 255 */ 0xff, /* => 352768.00 */
/* 1744830464.00 => 255 */ 0xff, /* => 352768.00 */
/* 1811939328.00 => 255 */ 0xff, /* => 352768.00 */
/* 1879048192.00 => 255 */ 0xff, /* => 352768.00 */
/* 1946157056.00 => 255 */ 0xff, /* => 352768.00 */
/* 2013265920.00 => 255 */ 0xff, /* => 352768.00 */
/* 2080374784.00 => 255 */ 0xff, /* => 352768.00 */
/* 2147483648.00 => 255 */ 0xff, /* => 352768.00 */
/* 2281701376.00 => 255 */ 0xff, /* => 352768.00 */
/* 2415919104.00 => 255 */ 0xff, /* => 352768.00 */
/* 2550136832.00 => 255 */ 0xff, /* => 352768.00 */
/* 2684354560.00 => 255 */ 0xff, /* => 352768.00 */
/* 2818572288.00 => 255 */ 0xff, /* => 352768.00 */
/* 2952790016.00 => 255 */ 0xff, /* => 352768.00 */
/* 3087007744.00 => 255 */ 0xff, /* => 352768.00 */
/* 3221225472.00 => 255 */ 0xff, /* => 352768.00 */
/* 3355443200.00 => 255 */ 0xff, /* => 352768.00 */
/* 3489660928.00 => 255 */ 0xff, /* => 352768.00 */
/* 3623878656.00 => 255 */ 0xff, /* => 352768.00 */
/* 3758096384.00 => 255 */ 0xff, /* => 352768.00 */
/* 3892314112.00 => 255 */ 0xff, /* => 352768.00 */
/* 4026531840.00 => 255 */ 0xff, /* => 352768.00 */
/* 4160749568.00 => 255 */ 0xff, /* => 352768.00 */
};
......@@ -207,7 +207,6 @@ static int lo_send(struct loop_device *lo, struct buffer_head *bh, int bsize,
index++;
pos += size;
UnlockPage(page);
deactivate_page(page);
page_cache_release(page);
}
return 0;
......@@ -218,7 +217,6 @@ static int lo_send(struct loop_device *lo, struct buffer_head *bh, int bsize,
kunmap(page);
unlock:
UnlockPage(page);
deactivate_page(page);
page_cache_release(page);
fail:
return -1;
......
......@@ -47,6 +47,7 @@
#include <linux/mca.h>
#include <linux/init.h>
#include <linux/ioport.h>
#include <linux/module.h>
#include <asm/system.h>
#include <asm/io.h>
......
......@@ -423,7 +423,7 @@ int DRM(mmap_dma)(struct file *filp, struct vm_area_struct *vma)
unlock_kernel();
vma->vm_ops = &DRM(vm_dma_ops);
vma->vm_flags |= VM_LOCKED | VM_SHM; /* Don't swap */
vma->vm_flags |= VM_RESERVED; /* Don't swap */
#if LINUX_VERSION_CODE < 0x020203 /* KERNEL_VERSION(2,2,3) */
/* In Linux 2.2.3 and above, this is
......@@ -558,7 +558,7 @@ int DRM(mmap)(struct file *filp, struct vm_area_struct *vma)
#endif
/* Don't let this area swap. Change when
DRM_KERNEL advisory is supported. */
vma->vm_flags |= VM_LOCKED;
vma->vm_flags |= VM_RESERVED;
break;
case _DRM_SCATTER_GATHER:
vma->vm_ops = &DRM(vm_sg_ops);
......@@ -567,12 +567,12 @@ int DRM(mmap)(struct file *filp, struct vm_area_struct *vma)
#else
vma->vm_pte = (unsigned long)map;
#endif
vma->vm_flags |= VM_LOCKED;
vma->vm_flags |= VM_RESERVED;
break;
default:
return -EINVAL; /* This should never happen. */
}
vma->vm_flags |= VM_LOCKED | VM_SHM; /* Don't swap */
vma->vm_flags |= VM_RESERVED; /* Don't swap */
#if LINUX_VERSION_CODE < 0x020203 /* KERNEL_VERSION(2,2,3) */
/* In Linux 2.2.3 and above, this is
......
......@@ -1284,7 +1284,7 @@ static int __init i2c_init(void)
#ifdef CONFIG_I2C_ALGOBIT
extern int i2c_algo_bit_init(void);
#endif
#ifdef CONFIG_I2C_CONFIG_I2C_PHILIPSPAR
#ifdef CONFIG_I2C_PHILIPSPAR
extern int i2c_bitlp_init(void);
#endif
#ifdef CONFIG_I2C_ELV
......
......@@ -873,7 +873,7 @@ static void jedec_flash_chip_scan(struct jedec_private *priv,unsigned long start
}
}
int __init jedec_probe_init(void)
static int __init jedec_probe_init(void)
{
register_mtd_chip_driver(&jedec_chipdrv);
return 0;
......
......@@ -422,7 +422,7 @@ static struct mtd_chip_driver jedec_chipdrv = {
module: THIS_MODULE
};
int __init jedec_probe_init(void)
static int __init jedec_probe_init(void)
{
register_mtd_chip_driver(&jedec_chipdrv);
return 0;
......
......@@ -4,11 +4,14 @@
* Copyright 1999, Thomas Davis, tadavis@lbl.gov.
* Licensed under the GPL. Based on dummy.c, and eql.c devices.
*
* bond.c: a bonding/etherchannel/sun trunking net driver
* bonding.c: an Ethernet Bonding driver
*
* This is useful to talk to a Cisco 5500, running Etherchannel, aka:
* Linux Channel Bonding
* This is useful to talk to a Cisco EtherChannel compatible equipment:
* Cisco 5500
* Sun Trunking (Solaris)
* Alteon AceDirector Trunks
* Linux Bonding
* and probably many L2 switches ...
*
* How it works:
* ifconfig bond0 ipaddress netmask up
......@@ -21,280 +24,2019 @@
* will release all slaves, marking them as down.
*
* ifenslave bond0 eth0
* will attache eth0 to bond0 as a slave. eth0 hw mac address will either
* 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
* will then be set from bond0.
* will then be set from bond0.
*
* v0.1 - first working version.
* v0.2 - changed stats to be calculated by summing slaves stats.
*
* Changes:
* Arnaldo Carvalho de Melo <acme@conectiva.com.br>
* - fix leaks on failure at bond_init
*
* 2000/09/30 - Willy Tarreau <willy at meta-x.org>
* - added trivial code to release a slave device.
* - fixed security bug (CAP_NET_ADMIN not checked)
* - implemented MII link monitoring to disable dead links :
* All MII capable slaves are checked every <miimon> milliseconds
* (100 ms seems good). This value can be changed by passing it to
* insmod. A value of zero disables the monitoring (default).
* - fixed an infinite loop in bond_xmit_roundrobin() when there's no
* good slave.
* - made the code hopefully SMP safe
*
* 2000/10/03 - Willy Tarreau <willy at meta-x.org>
* - optimized slave lists based on relevant suggestions from Thomas Davis
* - implemented active-backup method to obtain HA with two switches:
* stay as long as possible on the same active interface, while we
* also monitor the backup one (MII link status) because we want to know
* if we are able to switch at any time. ( pass "mode=1" to insmod )
* - lots of stress testings because we need it to be more robust than the
* wires ! :->
*
* 2000/10/09 - Willy Tarreau <willy at meta-x.org>
* - added up and down delays after link state change.
* - optimized the slaves chaining so that when we run forward, we never
* repass through the bond itself, but we can find it by searching
* backwards. Renders the deletion more difficult, but accelerates the
* scan.
* - smarter enslaving and releasing.
* - finer and more robust SMP locking
*
* 2000/10/17 - Willy Tarreau <willy at meta-x.org>
* - fixed two potential SMP race conditions
*
* 2000/10/18 - Willy Tarreau <willy at meta-x.org>
* - small fixes to the monitoring FSM in case of zero delays
* 2000/11/01 - Willy Tarreau <willy at meta-x.org>
* - fixed first slave not automatically used in trunk mode.
* 2000/11/10 : spelling of "EtherChannel" corrected.
* 2000/11/13 : fixed a race condition in case of concurrent accesses to ioctl().
* 2000/12/16 : fixed improper usage of rtnl_exlock_nowait().
*
* 2001/1/3 - Chad N. Tindel <ctindel at ieee dot org>
* - The bonding driver now simulates MII status monitoring, just like
* a normal network device. It will show that the link is down iff
* every slave in the bond shows that their links are down. If at least
* one slave is up, the bond's MII status will appear as up.
*
* 2001/2/7 - Chad N. Tindel <ctindel at ieee dot org>
* - Applications can now query the bond from user space to get
* information which may be useful. They do this by calling
* the BOND_INFO_QUERY ioctl. Once the app knows how many slaves
* are in the bond, it can call the BOND_SLAVE_INFO_QUERY ioctl to
* get slave specific information (# link failures, etc). See
* <linux/if_bonding.h> for more details. The structs of interest
* are ifbond and ifslave.
*
* 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
* first attempting a lock
* - Called SET_MODULE_OWNER for bond device
*
* 2001/5/17 - Tim Anderson <tsa at mvista.com>
* - 2 paths for releasing for slave release; 1 through ioctl
* and 2) through close. Both paths need to release the same way.
* - the free slave in bond release is changing slave status before
* the free. The netdev_set_master() is intended to change slave state
* so it should not be done as part of the release process.
* - Simple rule for slave state at release: only the active in A/B and
* only one in the trunked case.
*
* 2001/6/01 - Tim Anderson <tsa at mvista.com>
* - Now call dev_close when releasing a slave so it doesn't screw up
* out routing table.
*
* 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.
* - Changed the locking when calling bond_close to prevent deadlock.
*
* 2001/8/05 - Janice Girouard <girouard at us.ibm.com>
* - correct problem where refcnt of slave is not incremented in bond_ioctl
* so the system hangs when halting.
* - correct locking problem when unable to malloc in bond_enslave.
* - adding bond_xmit_xor logic.
* - adding multiple bond device support.
*
* 2001/8/13 - Erik Habbinga <erik_habbinga at hp dot com>
* - correct locking problem with rtnl_exlock_nowait
*
* 2001/8/23 - Janice Girouard <girouard at us.ibm.com>
* - bzero initial dev_bonds, to correct oops
* - convert SIOCDEVPRIVATE to new MII ioctl calls
*
* 2001/9/13 - Takao Indoh <indou dot takao at jp dot fujitsu dot com>
* - Add the BOND_CHANGE_ACTIVE ioctl implementation
*
* 2001/9/14 - Mark Huth <mhuth at mvista dot com>
* - Change MII_LINK_READY to not check for end of auto-negotiation,
* 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
* structure.
*
* 2001/9/25 - Janice Girouard <girouard at us.ibm.com>
* - add arp_monitor for active backup mode
*
* 2001/10/23 - Takao Indoh <indou dot takao at jp dot fujitsu dot com>
* - Various memory leak fixes
*/
#include <linux/module.h>
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/netdevice.h>
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/types.h>
#include <linux/fcntl.h>
#include <linux/interrupt.h>
#include <linux/ptrace.h>
#include <linux/ioport.h>
#include <linux/in.h>
#include <linux/malloc.h>
#include <linux/string.h>
#include <linux/init.h>
#include <linux/timer.h>
#include <linux/socket.h>
#include <asm/system.h>
#include <asm/bitops.h>
#include <asm/io.h>
#include <asm/dma.h>
#include <asm/uaccess.h>
#include <linux/errno.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
#include <net/sock.h>
#include <linux/rtnetlink.h>
#include <linux/if_bonding.h>
#include <linux/smp.h>
#include <limits.h>
#include <linux/if_ether.h>
#include <linux/if_arp.h>
/* monitor all links that often (in milliseconds). <=0 disables monitoring */
#ifndef BOND_LINK_MON_INTERV
#define BOND_LINK_MON_INTERV 0
#endif
#undef MII_LINK_UP
#define MII_LINK_UP 0x04
#undef MII_ENDOF_NWAY
#define MII_ENDOF_NWAY 0x20
#undef MII_LINK_READY
/*#define MII_LINK_READY (MII_LINK_UP | MII_ENDOF_NWAY)*/
#define MII_LINK_READY (MII_LINK_UP)
#define MAX_BOND_ADDR 256
#ifndef BOND_LINK_ARP_INTERV
#define BOND_LINK_ARP_INTERV 0
#endif
static int arp_interval = BOND_LINK_ARP_INTERV;
static char *arp_ip_target = NULL;
static unsigned long arp_target = 0;
static u32 my_ip = 0;
char *arp_target_hw_addr = NULL;
static int max_bonds = MAX_BONDS;
static int miimon = BOND_LINK_MON_INTERV;
static int mode = BOND_MODE_ROUNDROBIN;
static int updelay = 0;
static int downdelay = 0;
static int first_pass = 1;
int bond_cnt;
static struct bonding *these_bonds = NULL;
static struct net_device *dev_bonds = NULL;
MODULE_PARM(max_bonds, "1-" __MODULE_STRING(INT_MAX) "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(mode, "i");
MODULE_PARM(arp_interval, "i");
MODULE_PARM_DESC(arp_interval, "arp interval in milliseconds");
MODULE_PARM(arp_ip_target, "1-12s");
MODULE_PARM_DESC(arp_ip_target, "arp target in n.n.n.n form");
MODULE_PARM_DESC(mode, "Mode of operation : 0 for round robin, 1 for active-backup, 2 for xor");
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");
extern void arp_send( int type, int ptype, u32 dest_ip, struct net_device *dev,
u32 src_ip, unsigned char *dest_hw, unsigned char *src_hw,
unsigned char *target_hw);
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 bond_arp_monitor(struct net_device *dev);
static int bond_event(struct notifier_block *this, unsigned long event, void *ptr);
static void bond_set_slave_inactive_flags(slave_t *slave);
static void bond_set_slave_active_flags(slave_t *slave);
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_sethwaddr(struct net_device *master, struct net_device *slave);
/*
* bond_get_info is the interface into the /proc filesystem. This is
* a different interface than the BOND_INFO_QUERY ioctl. That is done
* through the generic networking ioctl interface, and bond_info_query
* is the internal function which provides that information.
*/
static int bond_get_info(char *buf, char **start, off_t offset, int length);
/* #define BONDING_DEBUG 1 */
/* several macros */
typedef struct slave
#define IS_UP(dev) ((((dev)->flags & (IFF_UP)) == (IFF_UP)) && \
(netif_running(dev) && netif_carrier_ok(dev)))
static void bond_set_slave_inactive_flags(slave_t *slave)
{
struct slave *next;
struct slave *prev;
struct net_device *dev;
} slave_t;
slave->state = BOND_STATE_BACKUP;
slave->dev->flags |= IFF_NOARP;
}
typedef struct bonding
static void bond_set_slave_active_flags(slave_t *slave)
{
slave_t *next;
slave_t *prev;
struct net_device *master;
slave->state = BOND_STATE_ACTIVE;
slave->dev->flags &= ~IFF_NOARP;
}
slave_t *current_slave;
struct net_device_stats stats;
} bonding_t;
/*
* 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's replaced with slave->next, or <bond> if not applicable.
*/
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 ? */
write_lock(&bond->ptrlock);
bond->current_slave = NULL; /* no slave anymore */
write_unlock(&bond->ptrlock);
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;
write_lock(&bond->ptrlock);
if (bond->current_slave == slave) {
bond->current_slave = slave->next;
}
write_unlock(&bond->ptrlock);
}
}
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;
}
static int bond_xmit(struct sk_buff *skb, struct net_device *dev);
static struct net_device_stats *bond_get_stats(struct net_device *dev);
write_lock(&bond->ptrlock);
if (bond->current_slave == slave) {
bond->current_slave = slave->next;
}
write_unlock(&bond->ptrlock);
}
static struct net_device *this_bond;
return slave;
}
static void release_one_slave(struct net_device *master, slave_t *slave)
/*
* if <dev> supports MII link status reporting, check its link
* and report it as a bit field in a short int :
* - 0x04 means link is up,
* - 0x20 means end of autonegociation
* If the device doesn't support MII, then we only report 0x24,
* meaning that the link is up and running since we can't check it.
*/
static u16 bond_check_dev_link(struct net_device *dev)
{
bonding_t *bond = master->priv;
static int (* ioctl)(struct net_device *, struct ifreq *, int);
struct ifreq ifr;
u16 *data = (u16 *)&ifr.ifr_data;
/* data[0] automagically filled by the ioctl */
data[1] = 1; /* MII location 1 reports Link Status */
if (((ioctl = dev->do_ioctl) != NULL) && /* ioctl to access MII */
(ioctl(dev, &ifr, SIOCGMIIPHY) == 0)) {
/* now, data[3] contains info about link status :
- data[3] & 0x04 means link up
- data[3] & 0x20 means end of auto-negociation
*/
return data[3];
} else {
return MII_LINK_READY; /* spoof link up ( we can't check it) */
}
}
spin_lock_bh(&master->xmit_lock);
if (bond->current_slave == slave)
bond->current_slave = slave->next;
slave->next->prev = slave->prev;
slave->prev->next = slave->next;
spin_unlock_bh(&master->xmit_lock);
static u16 bond_check_mii_link(bonding_t *bond)
{
int has_active_interface = 0;
netdev_set_master(slave->dev, NULL);
read_lock(&bond->ptrlock);
has_active_interface = (bond->current_slave != NULL);
read_unlock(&bond->ptrlock);
dev_put(slave->dev);
kfree(slave);
return (has_active_interface ? MII_LINK_READY : 0);
}
static int bond_open(struct net_device *dev)
{
struct timer_list *timer = &((struct bonding *)(dev->priv))->mii_timer;
struct timer_list *arp_timer = &((struct bonding *)(dev->priv))->arp_timer;
MOD_INC_USE_COUNT;
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;
arp_timer->function = (void *)&bond_arp_monitor;
add_timer(arp_timer);
}
return 0;
}
static int bond_close(struct net_device *master)
{
bonding_t *bond = master->priv;
bonding_t *bond = (struct bonding *) master->priv;
slave_t *slave;
unsigned long flags;
write_lock_irqsave(&bond->lock, flags);
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);
}
/* We need to unlock this because bond_release will re-lock it */
write_unlock_irqrestore(&bond->lock, flags);
while ((slave = bond->next) != (slave_t*)bond)
release_one_slave(master, slave);
/* Release the bonded slaves */
while ((slave = bond->prev) != (slave_t *)bond) {
bond_release(master, slave->dev);
}
MOD_DEC_USE_COUNT;
return 0;
}
static void bond_set_multicast_list(struct net_device *master)
static void set_multicast_list(struct net_device *master)
{
/*
bonding_t *bond = master->priv;
slave_t *slave;
for (slave = bond->next; slave != (slave_t*)bond; slave = slave->next) {
slave->dev->mc_list = master->mc_list;
slave->dev->mc_count = master->mc_count;
slave->dev->flags = master->flags;
slave->dev->set_multicast_list(slave->dev);
}
*/
}
static int bond_enslave(struct net_device *master, struct net_device *dev)
/*
* This function counts the the number of attached
* slaves for use by bond_xmit_xor.
*/
static void update_slave_cnt(bonding_t *bond)
{
int err;
bonding_t *bond = master->priv;
slave_t *slave;
slave_t *slave = NULL;
if (dev->type != master->type)
bond->slave_cnt = 0;
for (slave = bond->prev; slave != (slave_t*)bond; slave = slave->prev) {
bond->slave_cnt++;
}
}
/* enslave device <slave> to bond device <master> */
static int bond_enslave(struct net_device *master_dev,
struct net_device *slave_dev)
{
bonding_t *bond = NULL;
slave_t *new_slave = NULL;
unsigned long flags = 0;
int ndx = 0;
int err = 0;
if (master_dev == NULL || slave_dev == NULL) {
return -ENODEV;
}
bond = (struct bonding *) master_dev->priv;
if ((slave = kmalloc(sizeof(slave_t), GFP_KERNEL)) == NULL)
if (slave_dev->do_ioctl == NULL) {
printk(KERN_DEBUG
"Warning : no link monitoring support for %s\n",
slave_dev->name);
}
write_lock_irqsave(&bond->lock, flags);
/* not running. */
if ((slave_dev->flags & IFF_UP) != IFF_UP) {
#ifdef BONDING_DEBUG
printk(KERN_CRIT "Error, slave_dev is not running\n");
#endif
write_unlock_irqrestore(&bond->lock, flags);
return -EINVAL;
}
/* 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
write_unlock_irqrestore(&bond->lock, flags);
return -EBUSY;
}
if ((new_slave = kmalloc(sizeof(slave_t), GFP_KERNEL)) == NULL) {
write_unlock_irqrestore(&bond->lock, flags);
return -ENOMEM;
}
memset(new_slave, 0, sizeof(slave_t));
memset(slave, 0, sizeof(slave_t));
err = netdev_set_master(slave_dev, master_dev);
err = netdev_set_master(dev, master);
if (err) {
kfree(slave);
return err;
#ifdef BONDING_DEBUG
printk(KERN_CRIT "Error %d calling netdev_set_master\n", err);
#endif
kfree(new_slave);
write_unlock_irqrestore(&bond->lock, flags);
return err;
}
slave->dev = dev;
spin_lock_bh(&master->xmit_lock);
new_slave->dev = slave_dev;
/*
* 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.
*/
new_slave->prev = bond->prev;
new_slave->prev->next = new_slave;
bond->prev = new_slave;
new_slave->next = bond->next;
new_slave->delay = 0;
new_slave->link_failure_count = 0;
/* check for initial state */
if ((miimon <= 0) || ((bond_check_dev_link(slave_dev) & MII_LINK_READY)
== MII_LINK_READY)) {
#ifdef BONDING_DEBUG
printk(KERN_CRIT "Initial state of slave_dev is BOND_LINK_UP\n");
#endif
new_slave->link = BOND_LINK_UP;
}
else {
#ifdef BONDING_DEBUG
printk(KERN_CRIT "Initial state of slave_dev is BOND_LINK_DOWN\n");
#endif
new_slave->link = BOND_LINK_DOWN;
}
dev_hold(dev);
/* 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 (mode == BOND_MODE_ACTIVEBACKUP) {
if (((bond->current_slave == NULL)
|| (bond->current_slave->dev->flags & IFF_NOARP))
&& (new_slave->link == BOND_LINK_UP)) {
#ifdef BONDING_DEBUG
printk(KERN_CRIT "This is the first active slave\n");
#endif
/* first slave or no active slave yet, and this link
is OK, so make this interface the active one */
bond->current_slave = new_slave;
bond_set_slave_active_flags(new_slave);
}
else {
#ifdef BONDING_DEBUG
printk(KERN_CRIT "This is just a backup slave\n");
#endif
bond_set_slave_inactive_flags(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;
if (bond->current_slave == NULL) {
bond->current_slave = new_slave;
}
}
slave->prev = bond->prev;
slave->next = (slave_t*)bond;
slave->prev->next = slave;
slave->next->prev = slave;
update_slave_cnt(bond);
write_unlock_irqrestore(&bond->lock, flags);
/*
* !!! This is to support old versions of ifenslave. We can remove
* this in 2.5 because our ifenslave takes care of this for us.
* We check to see if the master has a mac address yet. If not,
* we'll give it the mac address of our slave device.
*/
for (ndx = 0; ndx < slave_dev->addr_len; ndx++) {
#ifdef BONDING_DEBUG
printk(KERN_CRIT "Checking ndx=%d of master_dev->dev_addr\n",
ndx);
#endif
if (master_dev->dev_addr[ndx] != 0) {
#ifdef BONDING_DEBUG
printk(KERN_CRIT "Found non-zero byte at ndx=%d\n",
ndx);
#endif
break;
}
}
if (ndx == slave_dev->addr_len) {
/*
* We got all the way through the address and it was
* all 0's.
*/
#ifdef BONDING_DEBUG
printk(KERN_CRIT "%s doesn't have a MAC address yet. ",
master_dev->name);
printk(KERN_CRIT "Going to give assign it from %s.\n",
slave_dev->name);
#endif
bond_sethwaddr(master_dev, slave_dev);
}
spin_unlock_bh(&master->xmit_lock);
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_UP ? "n up" : " down");
return 0;
}
static int bond_release(struct net_device *master, struct net_device *dev)
/*
* 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 = master->priv;
bonding_t *bond;
slave_t *slave;
slave_t *oldactive = NULL;
slave_t *newactive = NULL;
unsigned long flags;
int ret = 0;
if (master_dev == NULL || slave_dev == NULL) {
return -ENODEV;
}
bond = (struct bonding *) master_dev->priv;
write_lock_irqsave(&bond->lock, flags);
slave = (slave_t *)bond;
oldactive = bond->current_slave;
while ((slave = slave->prev) != (slave_t *)bond) {
if(slave_dev == slave->dev) {
newactive = slave;
break;
}
}
if ((newactive != NULL)&&
(oldactive != NULL)&&
(newactive != oldactive)&&
(newactive->link == BOND_LINK_UP)&&
IS_UP(newactive->dev)) {
bond_set_slave_inactive_flags(oldactive);
bond_set_slave_active_flags(newactive);
bond->current_slave = newactive;
printk("%s : activate %s(old : %s)\n",
master_dev->name, newactive->dev->name,
oldactive->dev->name);
}
else {
ret = -EINVAL;
}
write_unlock_irqrestore(&bond->lock, flags);
return ret;
}
/* Choose a new valid interface from the pool, set it active
* and make it the current slave. If no valid interface is
* found, the oldest slave in BACK state is choosen and
* activated. If none is found, it's considered as no
* interfaces left so the current slave is set to NULL.
* The result is a pointer to the current slave.
*
* Since this function sends messages tails through printk, the caller
* must have started something like `printk(KERN_INFO "xxxx ");'.
*
* Warning: must put locks around the call to this function if needed.
*/
slave_t *change_active_interface(bonding_t *bond)
{
slave_t *newslave, *oldslave;
slave_t *bestslave = NULL;
int mintime;
read_lock(&bond->ptrlock);
newslave = oldslave = bond->current_slave;
read_unlock(&bond->ptrlock);
if (newslave == NULL) { /* there were no active slaves left */
if (bond->next != (slave_t *)bond) { /* found one slave */
write_lock(&bond->ptrlock);
newslave = bond->current_slave = bond->next;
write_unlock(&bond->ptrlock);
} else {
printk (" but could not find any %s interface.\n",
(mode == BOND_MODE_ACTIVEBACKUP) ? "backup":"other");
write_lock(&bond->ptrlock);
bond->current_slave = (slave_t *)NULL;
write_unlock(&bond->ptrlock);
return NULL; /* still no slave, return NULL */
}
}
mintime = updelay;
do {
if (IS_UP(newslave->dev)) {
if (newslave->link == BOND_LINK_UP) {
/* this one is immediately usable */
if (mode == BOND_MODE_ACTIVEBACKUP) {
bond_set_slave_active_flags(newslave);
printk (" and making interface %s the active one.\n",
newslave->dev->name);
}
else {
printk (" and setting pointer to interface %s.\n",
newslave->dev->name);
}
write_lock(&bond->ptrlock);
bond->current_slave = newslave;
write_unlock(&bond->ptrlock);
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);
/* no usable backup found, we'll see if we at least got a link that was
coming back for a long time, and could possibly already be usable.
*/
if (bestslave != NULL) {
/* early take-over. */
printk (" and making interface %s the active one %d ms earlier.\n",
bestslave->dev->name,
(updelay - bestslave->delay)*miimon);
bestslave->delay = 0;
bestslave->link = BOND_LINK_UP;
bond_set_slave_active_flags(bestslave);
write_lock(&bond->ptrlock);
bond->current_slave = bestslave;
write_unlock(&bond->ptrlock);
return bestslave;
}
printk (" but could not find any %s interface.\n",
(mode == BOND_MODE_ACTIVEBACKUP) ? "backup":"other");
/* absolutely nothing found. let's return NULL */
write_lock(&bond->ptrlock);
bond->current_slave = (slave_t *)NULL;
write_unlock(&bond->ptrlock);
return NULL;
}
/*
* 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
* is write-locked.
*
* The rules for slave state should be:
* for Active/Backup:
* Active stays on all backups go down
* 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)
{
bonding_t *bond;
slave_t *our_slave, *old_current;
unsigned long flags;
if (master == NULL || slave == NULL) {
return -ENODEV;
}
if (dev->master != master)
bond = (struct bonding *) master->priv;
write_lock_irqsave(&bond->lock, flags);
/* 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);
write_unlock_irqrestore(&bond->lock, flags);
return -EINVAL;
}
for (slave = bond->next; slave != (slave_t*)bond; slave = slave->next) {
if (slave->dev == dev) {
release_one_slave(master, slave);
our_slave = (slave_t *)bond;
old_current = bond->current_slave;
while ((our_slave = our_slave->prev) != (slave_t *)bond) {
if (our_slave->dev == slave) {
bond_detach_slave(bond, our_slave);
printk (KERN_INFO "%s: releasing %s interface %s",
master->name,
(our_slave->state == BOND_STATE_ACTIVE) ? "active" : "backup",
slave->name);
if (our_slave == old_current) {
/* find a new interface and be verbose */
change_active_interface(bond);
} else {
printk(".\n");
}
kfree(our_slave);
/* release the slave from its bond */
netdev_set_master(slave, NULL);
/* only restore its RUNNING flag if monitoring set it down */
if (slave->flags & IFF_UP) {
slave->flags |= IFF_RUNNING;
}
if (slave->flags & IFF_NOARP ||
bond->current_slave != NULL) {
dev_close(slave);
}
if (bond->current_slave == NULL) {
printk(KERN_INFO
"%s: now running without any active interface !\n",
master->name);
}
update_slave_cnt(bond);
write_unlock_irqrestore(&bond->lock, flags);
return 0; /* deletion OK */
}
}
/* if we get here, it's because the device was not found */
write_unlock_irqrestore(&bond->lock, flags);
printk (KERN_INFO "%s: %s not enslaved\n", master->name, slave->name);
return -EINVAL;
}
/* this function is called regularly to monitor each slave's link. */
static void bond_mii_monitor(struct net_device *master)
{
bonding_t *bond = (struct bonding *) master->priv;
slave_t *slave, *bestslave, *oldcurrent;
unsigned long flags;
int slave_died = 0;
read_lock_irqsave(&bond->lock, flags);
if (rtnl_shlock_nowait()) {
goto monitor_out;
}
if (rtnl_exlock_nowait()) {
rtnl_shunlock();
goto monitor_out;
}
/* 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.
*/
bestslave = NULL;
slave = (slave_t *)bond;
read_lock(&bond->ptrlock);
oldcurrent = bond->current_slave;
read_unlock(&bond->ptrlock);
while ((slave = slave->prev) != (slave_t *)bond) {
/* use updelay+1 to match an UP slave even when updelay is 0 */
int mindelay = updelay + 1;
struct net_device *dev = slave->dev;
u16 link_state;
link_state = bond_check_dev_link(dev);
switch (slave->link) {
case BOND_LINK_UP: /* the link was up */
if ((link_state & MII_LINK_UP) == MII_LINK_UP) {
/* link stays up, tell that this one
is immediately available */
if (IS_UP(dev) && (mindelay > -2)) {
/* -2 is the best case :
this slave was already up */
mindelay = -2;
bestslave = slave;
}
break;
}
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)
? ((mode == BOND_MODE_ACTIVEBACKUP)
? ((slave == oldcurrent)
? "active " : "backup ")
: "")
: "idle ",
dev->name,
downdelay * miimon);
}
}
/* no break ! fall through the BOND_LINK_FAIL test to
ensure proper action to be taken
*/
case BOND_LINK_FAIL: /* the link has just gone down */
if ((link_state & MII_LINK_UP) == 0) {
/* link stays down */
if (slave->delay <= 0) {
/* link down for too long time */
slave->link = BOND_LINK_DOWN;
/* in active/backup mode, we must
completely disable this interface */
if (mode == BOND_MODE_ACTIVEBACKUP) {
bond_set_slave_inactive_flags(slave);
}
printk(KERN_INFO
"%s: link status definitely down "
"for interface %s, disabling it",
master->name,
dev->name);
read_lock(&bond->ptrlock);
if (slave == bond->current_slave) {
read_unlock(&bond->ptrlock);
/* find a new interface and be verbose */
change_active_interface(bond);
} else {
read_unlock(&bond->ptrlock);
printk(".\n");
}
slave_died = 1;
} else {
slave->delay--;
}
} else if ((link_state & MII_LINK_READY) == MII_LINK_READY) {
/* link up again */
slave->link = BOND_LINK_UP;
printk(KERN_INFO
"%s: link status up again after %d ms "
"for interface %s.\n",
master->name,
(downdelay - slave->delay) * miimon,
dev->name);
if (IS_UP(dev) && (mindelay > -1)) {
/* -1 is a good case : this slave went
down only for a short time */
mindelay = -1;
bestslave = slave;
}
}
break;
case BOND_LINK_DOWN: /* the link was down */
if ((link_state & MII_LINK_READY) != MII_LINK_READY) {
/* the link stays down, nothing more to do */
break;
} else { /* link going up */
slave->link = BOND_LINK_BACK;
slave->delay = updelay;
if (updelay > 0) {
/* 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);
}
}
/* no break ! fall through the BOND_LINK_BACK state in
case there's something to do.
*/
case BOND_LINK_BACK: /* the link has just come back */
if ((link_state & MII_LINK_UP) == 0) {
/* 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);
}
else if ((link_state & MII_LINK_READY) == MII_LINK_READY) {
/* link stays up */
if (slave->delay == 0) {
/* now the link has been up for long time enough */
slave->link = BOND_LINK_UP;
if (mode == BOND_MODE_ACTIVEBACKUP) {
/* prevent it from being the active one */
slave->state = BOND_STATE_BACKUP;
}
else {
/* make it immediately active */
slave->state = BOND_STATE_ACTIVE;
}
printk(KERN_INFO
"%s: link status definitely up "
"for interface %s.\n",
master->name,
dev->name);
}
else
slave->delay--;
/* we'll also look for the mostly eligible slave */
if (IS_UP(dev) && (slave->delay < mindelay)) {
mindelay = slave->delay;
bestslave = slave;
}
}
break;
} /* end of switch */
} /* end of while */
/* if there's no active interface and we discovered that one
of the slaves could be activated earlier, so we do it.
*/
read_lock(&bond->ptrlock);
oldcurrent = bond->current_slave;
read_unlock(&bond->ptrlock);
if (oldcurrent == NULL) { /* no active interface at the moment */
if (bestslave != NULL) { /* last chance to find one ? */
if (bestslave->link == BOND_LINK_UP) {
printk (KERN_INFO
"%s: making interface %s the new active one.\n",
master->name, bestslave->dev->name);
} else {
printk (KERN_INFO
"%s: making interface %s the new "
"active one %d ms earlier.\n",
master->name, bestslave->dev->name,
(updelay - bestslave->delay) * miimon);
bestslave->delay= 0;
bestslave->link = BOND_LINK_UP;
}
if (mode == BOND_MODE_ACTIVEBACKUP) {
bond_set_slave_active_flags(bestslave);
} else {
bestslave->state = BOND_STATE_ACTIVE;
}
write_lock(&bond->ptrlock);
bond->current_slave = bestslave;
write_unlock(&bond->ptrlock);
} else if (slave_died) {
/* print this message only once a slave has just died */
printk(KERN_INFO
"%s: now running without any active interface !\n",
master->name);
}
}
return 0;
rtnl_exunlock();
rtnl_shunlock();
monitor_out:
read_unlock_irqrestore(&bond->lock, flags);
/* re-arm the timer */
mod_timer(&bond->mii_timer, jiffies + (miimon * HZ / 1000));
}
/* It is pretty silly, SIOCSIFHWADDR exists to make this. */
/*
* this function is called regularly to monitor each slave's link
* insuring that traffic is being sent and received. If the adapter
* has been dormant, then an arp is transmitted to generate traffic
*/
static void bond_arp_monitor(struct net_device *master)
{
bonding_t *bond;
unsigned long flags;
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;
}
read_lock_irqsave(&bond->lock, flags);
if (!IS_UP(master)) {
mod_timer(&bond->arp_timer, next_timer);
goto monitor_out;
}
if (rtnl_shlock_nowait()) {
goto monitor_out;
}
if (rtnl_exlock_nowait()) {
rtnl_shunlock();
goto monitor_out;
}
/* see if any of the previous devices are up now (i.e. they have seen a
* response from an arp request sent by another adapter, since they
* have the same hardware address).
*/
slave = (slave_t *)bond;
while ((slave = slave->prev) != (slave_t *)bond) {
read_lock(&bond->ptrlock);
if ( (!(slave->link == BOND_LINK_UP))
&& (slave!= bond->current_slave) ) {
read_unlock(&bond->ptrlock);
if ( ((jiffies - slave->dev->trans_start) <=
the_delta_in_ticks) &&
((jiffies - slave->dev->last_rx) <=
the_delta_in_ticks) ) {
slave->link = BOND_LINK_UP;
write_lock(&bond->ptrlock);
if (bond->current_slave == NULL) {
slave->state = BOND_STATE_ACTIVE;
bond->current_slave = slave;
}
if (slave!=bond->current_slave) {
slave->dev->flags |= IFF_NOARP;
}
write_unlock(&bond->ptrlock);
} else {
if ((jiffies - slave->dev->last_rx) <=
the_delta_in_ticks) {
arp_send(ARPOP_REQUEST, ETH_P_ARP,
arp_target, slave->dev,
my_ip, arp_target_hw_addr,
slave->dev->dev_addr,
arp_target_hw_addr);
}
}
} else
read_unlock(&bond->ptrlock);
}
read_lock(&bond->ptrlock);
slave = bond->current_slave;
read_unlock(&bond->ptrlock);
if (slave != 0) {
/* see if you need to take down the current_slave, since
* you haven't seen an arp in 2*arp_intervals
*/
if ( ((jiffies - slave->dev->trans_start) >=
(2*the_delta_in_ticks)) ||
((jiffies - slave->dev->last_rx) >=
(2*the_delta_in_ticks)) ) {
if (slave->link == BOND_LINK_UP) {
slave->link = BOND_LINK_DOWN;
slave->state = BOND_STATE_BACKUP;
/*
* we want to see arps, otherwise we couldn't
* bring the adapter back online...
*/
printk(KERN_INFO "%s: link status definitely "
"down for interface %s, "
"disabling it",
slave->dev->master->name,
slave->dev->name);
/* find a new interface and be verbose */
change_active_interface(bond);
read_lock(&bond->ptrlock);
slave = bond->current_slave;
read_unlock(&bond->ptrlock);
}
}
/*
* ok, we know up/down, so just send a arp out if there has
* been no activity for a while
*/
if (slave != NULL ) {
if ( ((jiffies - slave->dev->trans_start) >=
the_delta_in_ticks) ||
((jiffies - slave->dev->last_rx) >=
the_delta_in_ticks) ) {
arp_send(ARPOP_REQUEST, ETH_P_ARP,
arp_target, slave->dev,
my_ip, arp_target_hw_addr,
slave->dev->dev_addr,
arp_target_hw_addr);
}
}
}
/* if we have no current slave.. try sending
* an arp on all of the interfaces
*/
if (bond->current_slave == NULL) {
slave = (slave_t *)bond;
while ((slave = slave->prev) != (slave_t *)bond) {
arp_send(ARPOP_REQUEST, ETH_P_ARP, arp_target,
slave->dev, my_ip, arp_target_hw_addr,
slave->dev->dev_addr, arp_target_hw_addr);
}
}
rtnl_exunlock();
rtnl_shunlock();
monitor_out:
read_unlock_irqrestore(&bond->lock, flags);
/* re-arm the timer */
mod_timer(&bond->arp_timer, next_timer);
}
#define isdigit(c) (c >= '0' && c <= '9')
__inline static int atoi( char **s)
{
int i=0;
while (isdigit(**s))
i = i*20 + *((*s)++) - '0';
return i;
}
#define isascii(c) (((unsigned char)(c))<=0x7f)
#define LF 0xA
#define isspace(c) (c==' ' || c==' '|| c==LF)
typedef uint32_t in_addr_t;
int
my_inet_aton(char *cp, unsigned long *the_addr) {
static const in_addr_t max[4] = { 0xffffffff, 0xffffff, 0xffff, 0xff };
in_addr_t val;
char c;
union iaddr {
uint8_t bytes[4];
uint32_t word;
} res;
uint8_t *pp = res.bytes;
int digit,base;
res.word = 0;
c = *cp;
for (;;) {
/*
* Collect number up to ``.''.
* Values are specified as for C:
* 0x=hex, 0=octal, isdigit=decimal.
*/
if (!isdigit(c)) goto ret_0;
val = 0; base = 10; digit = 0;
for (;;) {
if (isdigit(c)) {
val = (val * base) + (c - '0');
c = *++cp;
digit = 1;
} else {
break;
}
}
if (c == '.') {
/*
* Internet format:
* a.b.c.d
* a.b.c (with c treated as 16 bits)
* a.b (with b treated as 24 bits)
*/
if (pp > res.bytes + 2 || val > 0xff) {
goto ret_0;
}
*pp++ = val;
c = *++cp;
} else
break;
}
/*
* Check for trailing characters.
*/
if (c != '\0' && (!isascii(c) || !isspace(c))) {
goto ret_0;
}
/*
* Did we get a valid digit?
*/
if (!digit) {
goto ret_0;
}
/* Check whether the last part is in its limits depending on
the number of parts in total. */
if (val > max[pp - res.bytes]) {
goto ret_0;
}
if (the_addr!= NULL) {
*the_addr = res.word | htonl (val);
}
return (1);
ret_0:
return (0);
}
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_ioctl(struct net_device *master, struct ifreq *ifr, int cmd)
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 = mode;
info->num_slaves = 0;
info->miimon = miimon;
read_lock(&bond->ptrlock);
for (slave = bond->prev; slave!=(slave_t *)bond; slave = slave->prev) {
info->num_slaves++;
}
read_unlock(&bond->ptrlock);
return 0;
}
static int bond_slave_info_query(struct net_device *master,
struct ifslave *info)
{
struct net_device *slave = __dev_get_by_name(ifr->ifr_slave);
bonding_t *bond = (struct bonding *) master->priv;
slave_t *slave;
int cur_ndx = 0;
if (slave == NULL)
if (info->slave_id < 0) {
return -ENODEV;
}
switch (cmd) {
case BOND_ENSLAVE:
return bond_enslave(master, slave);
case BOND_RELEASE:
return bond_release(master, slave);
case BOND_SETHWADDR:
return bond_sethwaddr(master, slave);
default:
return -EOPNOTSUPP;
read_lock(&bond->ptrlock);
for (slave = bond->prev;
slave != (slave_t *)bond && cur_ndx < info->slave_id;
slave = slave->prev) {
cur_ndx++;
}
if (cur_ndx == info->slave_id) {
strcpy(info->slave_name, slave->dev->name);
info->link = slave->link;
info->state = slave->state;
info->link_failure_count = slave->link_failure_count;
} else {
read_unlock(&bond->ptrlock);
return -ENODEV;
}
read_unlock(&bond->ptrlock);
return 0;
}
static int bond_event(struct notifier_block *this, unsigned long event, void *ptr)
static int bond_ioctl(struct net_device *master_dev, struct ifreq *ifr, int cmd)
{
struct net_device *slave = ptr;
struct net_device *slave_dev = NULL;
struct ifbond *u_binfo = NULL, k_binfo;
struct ifslave *u_sinfo = NULL, k_sinfo;
u16 *data = NULL;
int ret = 0;
if (this_bond == NULL ||
this_bond == slave ||
this_bond != slave->master)
return NOTIFY_DONE;
#ifdef BONDING_DEBUG
printk(KERN_INFO "bond_ioctl: master=%s, cmd=%d\n",
master_dev->name, cmd);
#endif
switch (event) {
case NETDEV_UNREGISTER:
bond_release(this_bond, slave);
switch (cmd) {
case SIOCGMIIPHY:
data = (u16 *)&ifr->ifr_data;
if (data == NULL) {
return -EINVAL;
}
data[0] = 0;
/* Fall Through */
case SIOCGMIIREG:
/*
* We do this again just in case we were called by SIOCGMIIREG
* instead of SIOCGMIIPHY.
*/
data = (u16 *)&ifr->ifr_data;
if (data == NULL) {
return -EINVAL;
}
if (data[1] == 1) {
data[3] = 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;
}
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
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 (mode == BOND_MODE_ACTIVEBACKUP) {
ret = bond_change_active(master_dev, slave_dev);
}
else {
ret = -EINVAL;
}
break;
default:
ret = -EOPNOTSUPP;
}
return NOTIFY_DONE;
if (slave_dev) {
/*
* Clear the module reference that was added by dev_get_by_name
*/
dev_put(slave_dev);
}
return ret;
}
static struct notifier_block bond_netdev_notifier={
notifier_call: bond_event
};
#ifdef CONFIG_NET_FASTROUTE
static int bond_accept_fastpath(struct net_device *dev, struct dst_entry *dst)
{
return -1;
}
#endif
static int __init bond_init(struct net_device *dev)
static int bond_xmit_roundrobin(struct sk_buff *skb, struct net_device *dev)
{
bonding_t *bond;
slave_t *slave, *start_at;
struct bonding *bond = (struct bonding *) dev->priv;
unsigned long flags;
bond = kmalloc(sizeof(struct bonding), GFP_KERNEL);
if (bond == NULL)
return -ENOMEM;
if (!IS_UP(dev)) { /* bond down */
dev_kfree_skb(skb);
return 0;
}
memset(bond, 0, sizeof(struct bonding));
bond->next = (slave_t*)bond;
bond->prev = (slave_t*)bond;
bond->master = dev;
bond->current_slave = (slave_t*)bond;
dev->priv = bond;
read_lock_irqsave(&bond->lock, flags);
/* Initialize the device structure. */
dev->hard_start_xmit = bond_xmit;
dev->get_stats = bond_get_stats;
dev->stop = bond_close;
dev->set_multicast_list = bond_set_multicast_list;
dev->do_ioctl = bond_ioctl;
read_lock(&bond->ptrlock);
slave = start_at = bond->current_slave;
read_unlock(&bond->ptrlock);
/* Fill in the fields of the device structure with ethernet-generic
values. */
ether_setup(dev);
dev->tx_queue_len = 0;
dev->flags |= IFF_MASTER;
if (slave == NULL) { /* we're at the root, get the first slave */
/* no suitable interface, frame not sent */
dev_kfree_skb(skb);
read_unlock_irqrestore(&bond->lock, flags);
return 0;
}
this_bond = dev;
do {
if (IS_UP(slave->dev)
&& (slave->link == BOND_LINK_UP)
&& (slave->state == BOND_STATE_ACTIVE)) {
register_netdevice_notifier(&bond_netdev_notifier);
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_irqrestore(&bond->lock, flags);
return 0;
}
} while ((slave = slave->next) != start_at);
/* no suitable interface, frame not sent */
dev_kfree_skb(skb);
read_unlock_irqrestore(&bond->lock, flags);
return 0;
}
static int bond_xmit(struct sk_buff *skb, struct net_device *dev)
/*
* 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)
{
bonding_t *bond = dev->priv;
slave_t *slave, *start_at;
int pkt_len = skb->len;
struct bonding *bond = (struct bonding *) dev->priv;
unsigned long flags;
struct ethhdr *data = (struct ethhdr *)skb->data;
int slave_no;
if (!IS_UP(dev)) { /* bond down */
dev_kfree_skb(skb);
return 0;
}
slave = start_at = bond->current_slave;
read_lock_irqsave(&bond->lock, flags);
read_lock(&bond->ptrlock);
slave = bond->prev;
/* we're at the root, get the first slave */
if ((slave == NULL) || (slave->dev == NULL)) {
/* no suitable interface, frame not sent */
read_unlock(&bond->ptrlock);
dev_kfree_skb(skb);
read_unlock_irqrestore(&bond->lock, flags);
return 0;
}
slave_no = (data->h_dest[5]^slave->dev->dev_addr[5]) % bond->slave_cnt;
read_unlock(&bond->ptrlock);
while ( (slave_no > 0) && (slave != (slave_t *)bond) ) {
slave = slave->prev;
slave_no--;
}
start_at = slave;
do {
if (slave == (slave_t*)bond)
continue;
if (IS_UP(slave->dev)
&& (slave->link == BOND_LINK_UP)
&& (slave->state == BOND_STATE_ACTIVE)) {
if (netif_running(slave->dev) && netif_carrier_ok(slave->dev)) {
bond->current_slave = slave->next;
skb->dev = slave->dev;
skb->priority = 1;
dev_queue_xmit(skb);
if (dev_queue_xmit(skb)) {
bond->stats.tx_dropped++;
} else {
bond->stats.tx_packets++;
bond->stats.tx_bytes += pkt_len;
}
read_unlock_irqrestore(&bond->lock, flags);
return 0;
}
} while ((slave = slave->next) != start_at);
bond->stats.tx_dropped++;
kfree_skb(skb);
/* no suitable interface, frame not sent */
dev_kfree_skb(skb);
read_unlock_irqrestore(&bond->lock, flags);
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;
unsigned long flags;
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 */
if ( (arp_interval > 0) && (arp_target_hw_addr==NULL) &&
(skb->protocol == __constant_htons(ETH_P_IP) ) ) {
struct ethhdr *eth_hdr =
(struct ethhdr *) (((char *)skb->data));
arp_target_hw_addr = kmalloc(ETH_ALEN, GFP_KERNEL);
memcpy(arp_target_hw_addr, eth_hdr->h_dest, ETH_ALEN);
}
read_lock_irqsave(&bond->lock, flags);
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_irqrestore(&bond->lock, flags);
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);
read_unlock_irqrestore(&bond->lock, flags);
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;
unsigned long flags;
memset(bond->stats, 0, sizeof(struct net_device_stats));
read_lock_irqsave(&bond->lock, flags);
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_irqrestore(&bond->lock, flags);
return stats;
}
static int bond_get_info(char *buf, char **start, off_t offset, int length)
{
bonding_t *bond = these_bonds;
int len = 0;
off_t begin = 0;
u16 link;
slave_t *slave = NULL;
while (bond != NULL) {
/*
* This function locks the mutex, so we can't lock it until
* afterwards
*/
link = bond_check_mii_link(bond);
read_lock(&bond->ptrlock);
len += sprintf(buf + len, "Bonding Mode: ");
len += sprintf(buf + len, "%s\n", mode ? "active-backup" : "load balancing");
if (mode == BOND_MODE_ACTIVEBACKUP) {
if (bond->current_slave != NULL) {
len += sprintf(buf + len,
"Currently Active Slave: %s\n",
bond->current_slave->dev->name);
}
}
len += sprintf(buf + len, "MII Status: ");
len += sprintf(buf + len,
link == MII_LINK_READY ? "up\n" : "down\n");
len += sprintf(buf + len, "MII Polling Interval (ms): %d\n",
miimon);
len += sprintf(buf + len, "Up Delay (ms): %d\n", updelay);
len += sprintf(buf + len, "Down Delay (ms): %d\n", downdelay);
for (slave = bond->prev; slave != (slave_t *)bond;
slave = slave->prev) {
len += sprintf(buf + len, "\nSlave Interface: %s\n", slave->dev->name);
len += sprintf(buf + len, "MII Status: ");
len += sprintf(buf + len,
slave->link == BOND_LINK_UP ?
"up\n" : "down\n");
len += sprintf(buf + len, "Link Failure Count: %d\n",
slave->link_failure_count);
}
/*
* Figure out the calcs for the /proc/net interface
*/
*start = buf + (offset - begin);
len -= (offset - begin);
if (len > length) {
len = length;
}
if (len < 0) {
len = 0;
}
read_unlock(&bond->ptrlock);
bond = bond->next_bond;
}
return len;
}
static int bond_event(struct notifier_block *this, unsigned long event,
void *ptr)
{
struct bonding *this_bond=(struct bonding *)these_bonds;
struct bonding *last_bond;
struct net_device *event_dev = (struct net_device *)ptr;
/* while there are bonds configured */
while (this_bond != NULL) {
if (this_bond == event_dev->priv ) {
switch (event) {
case NETDEV_UNREGISTER:
/*
* remove this bond from a linked list of
* bonds
*/
if (this_bond == these_bonds) {
these_bonds = this_bond->next_bond;
} else {
for (last_bond = these_bonds;
last_bond != NULL;
last_bond = last_bond->next_bond) {
if (last_bond->next_bond ==
this_bond) {
last_bond->next_bond =
this_bond->next_bond;
}
}
}
return NOTIFY_DONE;
default:
return NOTIFY_DONE;
}
}
this_bond = this_bond->next_bond;
}
return NOTIFY_DONE;
}
static struct notifier_block bond_netdev_notifier={
bond_event,
NULL,
0
};
static int __init bond_init(struct net_device *dev)
{
bonding_t *bond, *this_bond, *last_bond;
#ifdef BONDING_DEBUG
printk (KERN_INFO "Begin bond_init for %s\n", dev->name);
#endif
bond = kmalloc(sizeof(struct bonding), GFP_KERNEL);
if (bond == NULL) {
return -ENOMEM;
}
memset(bond, 0, sizeof(struct bonding));
/* initialize rwlocks */
rwlock_init(&bond->lock);
rwlock_init(&bond->ptrlock);
bond->stats = kmalloc(sizeof(struct net_device_stats), GFP_KERNEL);
if (bond->stats == NULL) {
kfree(bond);
return -ENOMEM;
}
memset(bond->stats, 0, sizeof(struct net_device_stats));
bond->next = bond->prev = (slave_t *)bond;
bond->current_slave = NULL;
bond->device = dev;
dev->priv = bond;
/* Initialize the device structure. */
if (mode == BOND_MODE_ACTIVEBACKUP) {
dev->hard_start_xmit = bond_xmit_activebackup;
} else if (mode == BOND_MODE_ROUNDROBIN) {
dev->hard_start_xmit = bond_xmit_roundrobin;
} else if (mode == BOND_MODE_XOR) {
dev->hard_start_xmit = bond_xmit_xor;
} else {
printk(KERN_ERR "Unknown bonding mode %d\n", mode);
kfree(bond->stats);
kfree(bond);
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;
/*
* Fill in the fields of the device structure with ethernet-generic
* values.
*/
return &bond->stats;
ether_setup(dev);
dev->tx_queue_len = 0;
dev->flags |= IFF_MASTER|IFF_MULTICAST;
#ifdef CONFIG_NET_FASTROUTE
dev->accept_fastpath = bond_accept_fastpath;
#endif
printk(KERN_INFO "%s registered with", dev->name);
if (miimon > 0) {
printk(" MII link monitoring set to %d ms", miimon);
updelay /= miimon;
downdelay /= miimon;
} else {
printk("out MII link monitoring");
}
printk(", in %s mode.\n",mode?"active-backup":"bonding");
#ifdef CONFIG_PROC_FS
bond->bond_proc_dir = proc_mkdir(dev->name, proc_net);
if (bond->bond_proc_dir == NULL) {
printk(KERN_ERR "%s: Cannot init /proc/net/%s/\n",
dev->name, dev->name);
kfree(bond->stats);
kfree(bond);
return -ENOMEM;
}
bond->bond_proc_info_file =
create_proc_info_entry("info", 0, bond->bond_proc_dir,
bond_get_info);
if (bond->bond_proc_info_file == NULL) {
printk(KERN_ERR "%s: Cannot init /proc/net/%s/info\n",
dev->name, dev->name);
remove_proc_entry(dev->name, proc_net);
kfree(bond->stats);
kfree(bond);
return -ENOMEM;
}
#endif /* CONFIG_PROC_FS */
if (first_pass == 1) {
these_bonds = bond;
register_netdevice_notifier(&bond_netdev_notifier);
first_pass = 0;
} else {
last_bond = these_bonds;
this_bond = these_bonds->next_bond;
while (this_bond != NULL) {
last_bond = this_bond;
this_bond = this_bond->next_bond;
}
last_bond->next_bond = bond;
}
return 0;
}
static struct net_device dev_bond;
/*
static int __init bond_probe(struct net_device *dev)
{
bond_init(dev);
return 0;
}
*/
static int __init bonding_init(void)
{
/* Find a name for this unit */
int no;
int err;
dev_bond.init = bond_init;
err = dev_alloc_name(&dev_bond,"bond%d");
if (err<0)
return err;
/* Find a name for this unit */
static struct net_device *dev_bond = NULL;
SET_MODULE_OWNER(&dev_bond);
if (register_netdev(&dev_bond) != 0)
return -EIO;
dev_bond = dev_bonds = kmalloc(max_bonds*sizeof(struct net_device),
GFP_KERNEL);
if (dev_bond == NULL) {
return -ENOMEM;
}
memset(dev_bonds, 0, max_bonds*sizeof(struct net_device));
if (arp_ip_target) {
if (my_inet_aton(arp_ip_target, &arp_target) == 0) {
arp_interval = 0;
}
}
for (no = 0; no < max_bonds; no++) {
dev_bond->init = bond_init;
err = dev_alloc_name(dev_bond,"bond%d");
if (err < 0) {
kfree(dev_bonds);
return err;
}
SET_MODULE_OWNER(dev_bond);
if (register_netdev(dev_bond) != 0) {
kfree(dev_bonds);
return -EIO;
}
dev_bond++;
}
return 0;
}
static void __exit bonding_exit(void)
{
unregister_netdevice_notifier(&bond_netdev_notifier);
struct net_device *dev_bond = dev_bonds;
struct bonding *bond;
int no;
unregister_netdev(&dev_bond);
kfree(dev_bond.priv);
unregister_netdevice_notifier(&bond_netdev_notifier);
for (no = 0; no < max_bonds; no++) {
#ifdef CONFIG_PROC_FS
bond = (struct bonding *) dev_bond->priv;
remove_proc_entry("info", bond->bond_proc_dir);
remove_proc_entry(dev_bond->name, proc_net);
#endif
unregister_netdev(dev_bond);
kfree(bond->stats);
kfree(dev_bond->priv);
dev_bond->priv = NULL;
dev_bond++;
}
kfree(dev_bonds);
}
module_init(bonding_init);
......
......@@ -4186,7 +4186,7 @@
14e4 0007 NetXtreme BCM5701 1000BaseSX
14e4 0008 NetXtreme BCM5701 1000BaseTX
14e4 8008 NetXtreme BCM5701 1000BaseTX
1647 NetXtreme BCM5701 Gigabit Ethernet
1647 NetXtreme BCM5703 Gigabit Ethernet
5820 BCM5820 Crypto Accelerator
14e5 Pixelfusion Ltd
14e6 SHINING Technology Inc
......
......@@ -44,9 +44,6 @@
#include "zisofs.h"
#define min(a,b) ((a)<(b)?(a):(b))
#define max(a,b) ((a)>(b)?(a):(b))
/* This should probably be global. */
static char zisofs_sink_page[PAGE_CACHE_SIZE];
......
......@@ -349,6 +349,10 @@ extern void __global_restore_flags(unsigned long);
void disable_hlt(void);
void enable_hlt(void);
extern unsigned long dmi_broken;
extern int is_sony_vaio_laptop;
#define BROKEN_ACPI_Sx 0x0001
#define BROKEN_INIT_AFTER_S1 0x0002
#endif
......@@ -113,6 +113,8 @@ extern inline int pci_dma_supported(struct pci_dev *hwdev, u64 mask)
return 1;
}
#define pci_dac_dma_supported(dev, mask) (0)
/* Return the index of the PCI controller for device PDEV. */
#define pci_controller_num(PDEV) (0)
......
......@@ -9,16 +9,94 @@
* (c) Copyright 1999, Thomas Davis, tadavis@lbl.gov
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
* of the GNU Public License, incorporated herein by reference.
*
*/
#ifndef _LINUX_IF_BONDING_H
#define _LINUX_IF_BONDING_H
#define BOND_ENSLAVE (SIOCDEVPRIVATE)
#define BOND_RELEASE (SIOCDEVPRIVATE + 1)
#define BOND_SETHWADDR (SIOCDEVPRIVATE + 2)
#ifdef __KERNEL__
#include <linux/timer.h>
#include <linux/if.h>
#include <linux/proc_fs.h>
#endif /* __KERNEL__ */
#include <linux/types.h>
/*
* We can remove these ioctl definitions in 2.5. People should use the
* SIOC*** versions of them instead
*/
#define BOND_ENSLAVE_OLD (SIOCDEVPRIVATE)
#define BOND_RELEASE_OLD (SIOCDEVPRIVATE + 1)
#define BOND_SETHWADDR_OLD (SIOCDEVPRIVATE + 2)
#define BOND_SLAVE_INFO_QUERY_OLD (SIOCDEVPRIVATE + 11)
#define BOND_INFO_QUERY_OLD (SIOCDEVPRIVATE + 12)
#define BOND_CHANGE_ACTIVE_OLD (SIOCDEVPRIVATE + 13)
#define BOND_CHECK_MII_STATUS (SIOCGMIIPHY)
#define BOND_MODE_ROUNDROBIN 0
#define BOND_MODE_ACTIVEBACKUP 1
#define BOND_MODE_XOR 2
/* each slave's link has 4 states */
#define BOND_LINK_UP 0 /* link is up and running */
#define BOND_LINK_FAIL 1 /* link has just gone down */
#define BOND_LINK_DOWN 2 /* link has been down for too long time */
#define BOND_LINK_BACK 3 /* link is going back */
/* each slave has several states */
#define BOND_STATE_ACTIVE 0 /* link is active */
#define BOND_STATE_BACKUP 1 /* link is backup */
#define MAX_BONDS 1 /* Maximum number of devices to support */
typedef struct ifbond {
__s32 bond_mode;
__s32 num_slaves;
__s32 miimon;
} 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;
__u32 link_failure_count;
} ifslave;
#ifdef __KERNEL__
typedef struct slave {
struct slave *next;
struct slave *prev;
struct net_device *dev;
short delay;
char link; /* one of BOND_LINK_XXXX */
char state; /* one of BOND_STATE_XXXX */
u32 link_failure_count;
} slave_t;
typedef struct bonding {
slave_t *next;
slave_t *prev;
slave_t *current_slave;
__s32 slave_cnt;
rwlock_t lock;
rwlock_t ptrlock;
struct timer_list mii_timer;
struct timer_list arp_timer;
struct net_device_stats *stats;
#ifdef CONFIG_PROC_FS
struct proc_dir_entry *bond_proc_dir;
struct proc_dir_entry *bond_proc_info_file;
#endif /* CONFIG_PROC_FS */
struct bonding *next_bond;
struct net_device *device;
} bonding_t;
#endif /* __KERNEL__ */
#endif /* _LINUX_BOND_H */
......
......@@ -60,9 +60,11 @@ extern unsigned long simple_strtoul(const char *,char **,unsigned int);
extern long simple_strtol(const char *,char **,unsigned int);
extern unsigned long long simple_strtoull(const char *,char **,unsigned int);
extern long long simple_strtoll(const char *,char **,unsigned int);
extern int sprintf(char * buf, const char * fmt, ...);
extern int sprintf(char * buf, const char * fmt, ...)
__attribute__ ((format (printf, 2, 3)));
extern int vsprintf(char *buf, const char *, va_list);
extern int snprintf(char * buf, size_t size, const char *fmt, ...);
extern int snprintf(char * buf, size_t size, const char * fmt, ...)
__attribute__ ((format (printf, 3, 4)));
extern int vsnprintf(char *buf, size_t size, const char *fmt, va_list args);
extern int sscanf(const char *, const char *, ...)
......
......@@ -271,8 +271,8 @@ typedef struct page {
#define PG_uptodate 3
#define PG_dirty 4
#define PG_unused 5
#define PG_active 6
#define PG_inactive 7
#define PG_lru 6
#define PG_active 7
#define PG_slab 8
#define PG_skip 10
#define PG_highmem 11
......@@ -320,14 +320,10 @@ extern void FASTCALL(set_page_dirty(struct page *));
#define PageActive(page) test_bit(PG_active, &(page)->flags)
#define SetPageActive(page) set_bit(PG_active, &(page)->flags)
#define ClearPageActive(page) clear_bit(PG_active, &(page)->flags)
#define TestandSetPageActive(page) test_and_set_bit(PG_active, &(page)->flags)
#define TestandClearPageActive(page) test_and_clear_bit(PG_active, &(page)->flags)
#define PageInactive(page) test_bit(PG_inactive, &(page)->flags)
#define SetPageInactive(page) set_bit(PG_inactive, &(page)->flags)
#define ClearPageInactive(page) clear_bit(PG_inactive, &(page)->flags)
#define TestandSetPageInactive(page) test_and_set_bit(PG_inactive, &(page)->flags)
#define TestandClearPageInactive(page) test_and_clear_bit(PG_inactive, &(page)->flags)
#define PageLRU(page) test_bit(PG_lru, &(page)->flags)
#define TestSetPageLRU(page) test_and_set_bit(PG_lru, &(page)->flags)
#define TestClearPageLRU(page) test_and_clear_bit(PG_lru, &(page)->flags)
#ifdef CONFIG_HIGHMEM
#define PageHighMem(page) test_bit(PG_highmem, &(page)->flags)
......
......@@ -1473,7 +1473,9 @@
#define PCI_DEVICE_ID_PANACOM_DUALMODEM 0x0402
#define PCI_VENDOR_ID_BROADCOM 0x14e4
#define PCI_DEVICE_ID_TIGON3 0x1644
#define PCI_DEVICE_ID_TIGON3_5700 0x1644
#define PCI_DEVICE_ID_TIGON3_5701 0x1645
#define PCI_DEVICE_ID_TIGON3_5703 0x1647
#define PCI_VENDOR_ID_SYBA 0x1592
#define PCI_DEVICE_ID_SYBA_2P_EPP 0x0782
......
......@@ -105,6 +105,15 @@
#define SIOCGIFVLAN 0x8982 /* 802.1Q VLAN support */
#define SIOCSIFVLAN 0x8983 /* Set 802.1Q VLAN options */
/* bonding calls */
#define SIOCBONDENSLAVE 0x8990 /* enslave a device to the bond */
#define SIOCBONDRELEASE 0x8991 /* release a slave from the bond*/
#define SIOCBONDSETHWADDR 0x8992 /* set the hw addr of the bond */
#define SIOCBONDSLAVEINFOQUERY 0x8993 /* rtn info about slave state */
#define SIOCBONDINFOQUERY 0x8994 /* rtn info about bond state */
#define SIOCBONDCHANGEACTIVE 0x8995 /* update to a new active slave */
/* Device private ioctl calls */
/*
......
......@@ -166,9 +166,9 @@ extern void FASTCALL(mark_page_accessed(struct page *));
*/
#define DEBUG_LRU_PAGE(page) \
do { \
if (PageActive(page)) \
if (!PageLRU(page)) \
BUG(); \
if (PageInactive(page)) \
if (PageActive(page)) \
BUG(); \
if (page_count(page) == 0) \
BUG(); \
......@@ -185,7 +185,6 @@ do { \
#define add_page_to_inactive_list(page) \
do { \
DEBUG_LRU_PAGE(page); \
SetPageInactive(page); \
list_add(&(page)->lru, &inactive_list); \
nr_inactive_pages++; \
} while (0)
......@@ -200,7 +199,6 @@ do { \
#define del_page_from_inactive_list(page) \
do { \
list_del(&(page)->lru); \
ClearPageInactive(page); \
nr_inactive_pages--; \
} while (0)
......
......@@ -80,9 +80,9 @@ static void __free_pages_ok (struct page *page, unsigned int order)
BUG();
if (PageLocked(page))
BUG();
if (PageActive(page))
if (PageLRU(page))
BUG();
if (PageInactive(page))
if (PageActive(page))
BUG();
page->flags &= ~((1<<PG_referenced) | (1<<PG_dirty));
......@@ -203,7 +203,10 @@ static struct page * rmqueue(zone_t *zone, unsigned int order)
set_page_count(page, 1);
if (BAD_RANGE(zone,page))
BUG();
DEBUG_LRU_PAGE(page);
if (PageLRU(page))
BUG();
if (PageActive(page))
BUG();
return page;
}
curr_order++;
......@@ -268,9 +271,9 @@ static struct page * balance_classzone(zone_t * classzone, unsigned int gfp_mask
BUG();
if (PageLocked(page))
BUG();
if (PageActive(page))
if (PageLRU(page))
BUG();
if (PageInactive(page))
if (PageActive(page))
BUG();
if (PageDirty(page))
BUG();
......@@ -425,7 +428,7 @@ unsigned long get_zeroed_page(unsigned int gfp_mask)
void page_cache_release(struct page *page)
{
if (!PageReserved(page) && put_page_testzero(page)) {
if (PageActive(page) || PageInactive(page))
if (PageLRU(page))
lru_cache_del(page);
__free_pages_ok(page, 0);
}
......
......@@ -38,7 +38,7 @@ pager_daemon_t pager_daemon = {
*/
static inline void activate_page_nolock(struct page * page)
{
if (PageInactive(page)) {
if (PageLRU(page) && !PageActive(page)) {
del_page_from_inactive_list(page);
add_page_to_active_list(page);
}
......@@ -57,7 +57,7 @@ void activate_page(struct page * page)
*/
void lru_cache_add(struct page * page)
{
if (!PageActive(page) && !PageInactive(page)) {
if (!TestSetPageLRU(page)) {
spin_lock(&pagemap_lru_lock);
add_page_to_inactive_list(page);
spin_unlock(&pagemap_lru_lock);
......@@ -73,12 +73,12 @@ void lru_cache_add(struct page * page)
*/
void __lru_cache_del(struct page * page)
{
if (PageActive(page)) {
del_page_from_active_list(page);
} else if (PageInactive(page)) {
del_page_from_inactive_list(page);
} else {
// printk("VM: __lru_cache_del, found unknown page ?!\n");
if (TestClearPageLRU(page)) {
if (PageActive(page)) {
del_page_from_active_list(page);
} else {
del_page_from_inactive_list(page);
}
}
}
......
......@@ -347,7 +347,9 @@ static int shrink_cache(int nr_pages, zone_t * classzone, unsigned int gfp_mask,
page = list_entry(entry, struct page, lru);
if (unlikely(!PageInactive(page)))
if (unlikely(!PageLRU(page)))
BUG();
if (unlikely(PageActive(page)))
BUG();
list_del(entry);
......
......@@ -565,11 +565,11 @@ int dev_alloc_name(struct net_device *dev, const char *name)
/*
* Verify the string as this thing may have come from
* the user. There must be one "%d" and no other "%"
* characters.
* the user. There must be either one "%d" and no other "%"
* characters, or no "%" characters at all.
*/
p = strchr(name, '%');
if (!p || p[1] != 'd' || strchr(p+2, '%'))
if (p && (p[1] != 'd' || strchr(p+2, '%')))
return -EINVAL;
/*
......@@ -2221,6 +2221,12 @@ static int dev_ifsioc(struct ifreq *ifr, unsigned int cmd)
default:
if ((cmd >= SIOCDEVPRIVATE &&
cmd <= SIOCDEVPRIVATE + 15) ||
cmd == SIOCBONDENSLAVE ||
cmd == SIOCBONDRELEASE ||
cmd == SIOCBONDSETHWADDR ||
cmd == SIOCBONDSLAVEINFOQUERY ||
cmd == SIOCBONDINFOQUERY ||
cmd == SIOCBONDCHANGEACTIVE ||
cmd == SIOCETHTOOL ||
cmd == SIOCGMIIPHY ||
cmd == SIOCGMIIREG ||
......@@ -2372,6 +2378,12 @@ int dev_ioctl(unsigned int cmd, void *arg)
case SIOCSIFTXQLEN:
case SIOCSIFNAME:
case SIOCSMIIREG:
case SIOCBONDENSLAVE:
case SIOCBONDRELEASE:
case SIOCBONDSETHWADDR:
case SIOCBONDSLAVEINFOQUERY:
case SIOCBONDINFOQUERY:
case SIOCBONDCHANGEACTIVE:
if (!capable(CAP_NET_ADMIN))
return -EPERM;
dev_load(ifr.ifr_name);
......
......@@ -3,7 +3,7 @@
*
* Alan Cox, <alan@redhat.com>
*
* Version: $Id: icmp.c,v 1.81 2001/09/01 00:31:50 davem Exp $
* Version: $Id: icmp.c,v 1.82 2001/11/01 23:44:31 davem Exp $
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
......@@ -139,7 +139,7 @@ struct icmp_err icmp_err_convert[] = {
{ EHOSTUNREACH, 1 } /* ICMP_PREC_CUTOFF */
};
/* Control parameters for ECHO relies. */
/* Control parameters for ECHO replies. */
int sysctl_icmp_echo_ignore_all;
int sysctl_icmp_echo_ignore_broadcasts;
......
......@@ -5,7 +5,7 @@
*
* The Internet Protocol (IP) module.
*
* Version: $Id: ip_input.c,v 1.53 2000/12/18 19:01:50 davem Exp $
* Version: $Id: ip_input.c,v 1.54 2001/11/06 22:33:52 davem Exp $
*
* Authors: Ross Biro, <bir7@leland.Stanford.Edu>
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
......@@ -383,7 +383,7 @@ static inline int ip_rcv_finish(struct sk_buff *skb)
*/
int ip_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt)
{
struct iphdr *iph = skb->nh.iph;
struct iphdr *iph;
/* When the interface is in promisc. mode, drop all the crap
* that it receives, do not try to analyse it.
......@@ -418,6 +418,8 @@ int ip_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt)
if (!pskb_may_pull(skb, iph->ihl*4))
goto inhdr_error;
iph = skb->nh.iph;
if (ip_fast_csum((u8 *)iph, iph->ihl) != 0)
goto inhdr_error;
......
......@@ -78,12 +78,20 @@ fw_in(unsigned int hooknum,
{
int ret = FW_BLOCK;
u_int16_t redirpt;
struct sk_buff *nskb;
/* Assume worse case: any hook could change packet */
(*pskb)->nfcache |= NFC_UNKNOWN | NFC_ALTERED;
if ((*pskb)->ip_summed == CHECKSUM_HW)
(*pskb)->ip_summed = CHECKSUM_NONE;
/* Firewall rules can alter TOS: raw socket may have clone of
skb: don't disturb it --RR */
nskb = skb_unshare(*pskb, GFP_ATOMIC);
if (!nskb)
return NF_DROP;
*pskb = nskb;
switch (hooknum) {
case NF_IP_PRE_ROUTING:
if (fwops->fw_acct_in)
......
......@@ -734,6 +734,15 @@ do_bindings(struct ip_conntrack *ct,
synchronize_bh()) can vanish. */
READ_LOCK(&ip_nat_lock);
for (i = 0; i < info->num_manips; i++) {
struct sk_buff *nskb;
/* raw socket may have clone of skb: don't disturb it --RR */
nskb = skb_unshare(*pskb, GFP_ATOMIC);
if (!nskb) {
READ_UNLOCK(&ip_nat_lock);
return NF_DROP;
}
*pskb = nskb;
if (info->manips[i].direction == dir
&& info->manips[i].hooknum == hooknum) {
DEBUGP("Mangling %p: %s to %u.%u.%u.%u %u\n",
......
......@@ -48,6 +48,13 @@ ipt_tcpmss_target(struct sk_buff **pskb,
u_int16_t tcplen, newtotlen, oldval, newmss;
unsigned int i;
u_int8_t *opt;
struct sk_buff *nskb;
/* raw socket may have clone of skb: don't disturb it --RR */
nskb = skb_unshare(*pskb, GFP_ATOMIC);
if (!nskb)
return NF_DROP;
*pskb = nskb;
tcplen = (*pskb)->len - iph->ihl*4;
......
......@@ -19,8 +19,15 @@ target(struct sk_buff **pskb,
const struct ipt_tos_target_info *tosinfo = targinfo;
if ((iph->tos & IPTOS_TOS_MASK) != tosinfo->tos) {
struct sk_buff *nskb;
u_int16_t diffs[2];
/* raw socket may have clone of skb: don't disturb it --RR */
nskb = skb_unshare(*pskb, GFP_ATOMIC);
if (!nskb)
return NF_DROP;
*pskb = nskb;
diffs[0] = htons(iph->tos) ^ 0xFFFF;
iph->tos = (iph->tos & IPTOS_PREC_MASK) | tosinfo->tos;
diffs[1] = htons(iph->tos);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment