sk98lin: resurrect driver
authorStephen Hemminger <shemminger@linux-foundation.org>
Sat, 15 Sep 2007 23:35:14 +0000 (19:35 -0400)
committerJeff Garzik <jeff@garzik.org>
Sat, 15 Sep 2007 23:35:14 +0000 (19:35 -0400)
This reverts commit e1abecc48938fbe1966ea6e78267fc673fa59295.

The driver works on some hardware that skge doesn't handle yet.

Signed-off-by: Stephen Hemminger <shemminger@linux-foundation.org>
Signed-off-by: Jeff Garzik <jeff@garzik.org>
45 files changed:
Documentation/feature-removal-schedule.txt
Documentation/networking/00-INDEX
Documentation/networking/sk98lin.txt [new file with mode: 0644]
drivers/net/Kconfig
drivers/net/Makefile
drivers/net/sk98lin/Makefile [new file with mode: 0644]
drivers/net/sk98lin/h/lm80.h [new file with mode: 0644]
drivers/net/sk98lin/h/skaddr.h [new file with mode: 0644]
drivers/net/sk98lin/h/skcsum.h [new file with mode: 0644]
drivers/net/sk98lin/h/skdebug.h [new file with mode: 0644]
drivers/net/sk98lin/h/skdrv1st.h [new file with mode: 0644]
drivers/net/sk98lin/h/skdrv2nd.h [new file with mode: 0644]
drivers/net/sk98lin/h/skerror.h [new file with mode: 0644]
drivers/net/sk98lin/h/skgedrv.h [new file with mode: 0644]
drivers/net/sk98lin/h/skgehw.h [new file with mode: 0644]
drivers/net/sk98lin/h/skgehwt.h [new file with mode: 0644]
drivers/net/sk98lin/h/skgei2c.h [new file with mode: 0644]
drivers/net/sk98lin/h/skgeinit.h [new file with mode: 0644]
drivers/net/sk98lin/h/skgepnm2.h [new file with mode: 0644]
drivers/net/sk98lin/h/skgepnmi.h [new file with mode: 0644]
drivers/net/sk98lin/h/skgesirq.h [new file with mode: 0644]
drivers/net/sk98lin/h/ski2c.h [new file with mode: 0644]
drivers/net/sk98lin/h/skqueue.h [new file with mode: 0644]
drivers/net/sk98lin/h/skrlmt.h [new file with mode: 0644]
drivers/net/sk98lin/h/sktimer.h [new file with mode: 0644]
drivers/net/sk98lin/h/sktypes.h [new file with mode: 0644]
drivers/net/sk98lin/h/skversion.h [new file with mode: 0644]
drivers/net/sk98lin/h/skvpd.h [new file with mode: 0644]
drivers/net/sk98lin/h/xmac_ii.h [new file with mode: 0644]
drivers/net/sk98lin/skaddr.c [new file with mode: 0644]
drivers/net/sk98lin/skdim.c [new file with mode: 0644]
drivers/net/sk98lin/skethtool.c [new file with mode: 0644]
drivers/net/sk98lin/skge.c [new file with mode: 0644]
drivers/net/sk98lin/skgehwt.c [new file with mode: 0644]
drivers/net/sk98lin/skgeinit.c [new file with mode: 0644]
drivers/net/sk98lin/skgemib.c [new file with mode: 0644]
drivers/net/sk98lin/skgepnmi.c [new file with mode: 0644]
drivers/net/sk98lin/skgesirq.c [new file with mode: 0644]
drivers/net/sk98lin/ski2c.c [new file with mode: 0644]
drivers/net/sk98lin/sklm80.c [new file with mode: 0644]
drivers/net/sk98lin/skqueue.c [new file with mode: 0644]
drivers/net/sk98lin/skrlmt.c [new file with mode: 0644]
drivers/net/sk98lin/sktimer.c [new file with mode: 0644]
drivers/net/sk98lin/skvpd.c [new file with mode: 0644]
drivers/net/sk98lin/skxmac2.c [new file with mode: 0644]

index b9a3fdc..00928d2 100644 (file)
@@ -298,3 +298,11 @@ Why:       All mthca hardware also supports MSI-X, which provides
 Who:   Roland Dreier <rolandd@cisco.com>
 
 ---------------------------
+
+What:   sk98lin network driver
+When:   Feburary 2008
+Why:    In kernel tree version of driver is unmaintained. Sk98lin driver
+       replaced by the skge driver. 
+Who:    Stephen Hemminger <shemminger@linux-foundation.org>
+
+---------------------------
index d63f480..153d84d 100644 (file)
@@ -96,6 +96,9 @@ routing.txt
        - the new routing mechanism
 shaper.txt
        - info on the module that can shape/limit transmitted traffic.
+sk98lin.txt
+       - Marvell Yukon Chipset / SysKonnect SK-98xx compliant Gigabit
+         Ethernet Adapter family driver info
 skfp.txt
        - SysKonnect FDDI (SK-5xxx, Compaq Netelligent) driver info.
 smc9.txt
diff --git a/Documentation/networking/sk98lin.txt b/Documentation/networking/sk98lin.txt
new file mode 100644 (file)
index 0000000..8590a95
--- /dev/null
@@ -0,0 +1,568 @@
+(C)Copyright 1999-2004 Marvell(R).
+All rights reserved
+===========================================================================
+
+sk98lin.txt created 13-Feb-2004
+
+Readme File for sk98lin v6.23
+Marvell Yukon/SysKonnect SK-98xx Gigabit Ethernet Adapter family driver for LINUX
+
+This file contains
+ 1  Overview
+ 2  Required Files
+ 3  Installation
+    3.1  Driver Installation
+    3.2  Inclusion of adapter at system start
+ 4  Driver Parameters
+    4.1  Per-Port Parameters
+    4.2  Adapter Parameters
+ 5  Large Frame Support
+ 6  VLAN and Link Aggregation Support (IEEE 802.1, 802.1q, 802.3ad)
+ 7  Troubleshooting
+
+===========================================================================
+
+
+1  Overview
+===========
+
+The sk98lin driver supports the Marvell Yukon and SysKonnect 
+SK-98xx/SK-95xx compliant Gigabit Ethernet Adapter on Linux. It has 
+been tested with Linux on Intel/x86 machines.
+***
+
+
+2  Required Files
+=================
+
+The linux kernel source.
+No additional files required.
+***
+
+
+3  Installation
+===============
+
+It is recommended to download the latest version of the driver from the 
+SysKonnect web site www.syskonnect.com. If you have downloaded the latest
+driver, the Linux kernel has to be patched before the driver can be 
+installed. For details on how to patch a Linux kernel, refer to the 
+patch.txt file.
+
+3.1  Driver Installation
+------------------------
+
+The following steps describe the actions that are required to install
+the driver and to start it manually. These steps should be carried
+out for the initial driver setup. Once confirmed to be ok, they can
+be included in the system start.
+
+NOTE 1: To perform the following tasks you need 'root' access.
+
+NOTE 2: In case of problems, please read the section "Troubleshooting" 
+        below.
+
+The driver can either be integrated into the kernel or it can be compiled 
+as a module. Select the appropriate option during the kernel 
+configuration.
+
+Compile/use the driver as a module
+----------------------------------
+To compile the driver, go to the directory /usr/src/linux and
+execute the command "make menuconfig" or "make xconfig" and proceed as 
+follows:
+
+To integrate the driver permanently into the kernel, proceed as follows:
+
+1. Select the menu "Network device support" and then "Ethernet(1000Mbit)"
+2. Mark "Marvell Yukon Chipset / SysKonnect SK-98xx family support" 
+   with (*) 
+3. Build a new kernel when the configuration of the above options is 
+   finished.
+4. Install the new kernel.
+5. Reboot your system.
+
+To use the driver as a module, proceed as follows:
+
+1. Enable 'loadable module support' in the kernel.
+2. For automatic driver start, enable the 'Kernel module loader'.
+3. Select the menu "Network device support" and then "Ethernet(1000Mbit)"
+4. Mark "Marvell Yukon Chipset / SysKonnect SK-98xx family support" 
+   with (M)
+5. Execute the command "make modules".
+6. Execute the command "make modules_install".
+   The appropriate modules will be installed.
+7. Reboot your system.
+
+
+Load the module manually
+------------------------
+To load the module manually, proceed as follows:
+
+1. Enter "modprobe sk98lin".
+2. If a Marvell Yukon or SysKonnect SK-98xx adapter is installed in 
+   your computer and you have a /proc file system, execute the command:
+   "ls /proc/net/sk98lin/" 
+   This should produce an output containing a line with the following 
+   format:
+   eth0   eth1  ...
+   which indicates that your adapter has been found and initialized.
+   
+   NOTE 1: If you have more than one Marvell Yukon or SysKonnect SK-98xx 
+           adapter installed, the adapters will be listed as 'eth0', 
+                   'eth1', 'eth2', etc.
+                   For each adapter, repeat steps 3 and 4 below.
+
+   NOTE 2: If you have other Ethernet adapters installed, your Marvell
+           Yukon or SysKonnect SK-98xx adapter will be mapped to the 
+                   next available number, e.g. 'eth1'. The mapping is executed 
+                   automatically.
+           The module installation message (displayed either in a system
+           log file or on the console) prints a line for each adapter 
+           found containing the corresponding 'ethX'.
+
+3. Select an IP address and assign it to the respective adapter by 
+   entering:
+   ifconfig eth0 <ip-address>
+   With this command, the adapter is connected to the Ethernet. 
+   
+   SK-98xx Gigabit Ethernet Server Adapters: The yellow LED on the adapter 
+   is now active, the link status LED of the primary port is active and 
+   the link status LED of the secondary port (on dual port adapters) is 
+   blinking (if the ports are connected to a switch or hub).
+   SK-98xx V2.0 Gigabit Ethernet Adapters: The link status LED is active.
+   In addition, you will receive a status message on the console stating
+   "ethX: network connection up using port Y" and showing the selected 
+   connection parameters (x stands for the ethernet device number 
+   (0,1,2, etc), y stands for the port name (A or B)).
+
+   NOTE: If you are in doubt about IP addresses, ask your network
+         administrator for assistance.
+  
+4. Your adapter should now be fully operational.
+   Use 'ping <otherstation>' to verify the connection to other computers 
+   on your network.
+5. To check the adapter configuration view /proc/net/sk98lin/[devicename].
+   For example by executing:    
+   "cat /proc/net/sk98lin/eth0" 
+
+Unload the module
+-----------------
+To stop and unload the driver modules, proceed as follows:
+
+1. Execute the command "ifconfig eth0 down".
+2. Execute the command "rmmod sk98lin".
+
+3.2  Inclusion of adapter at system start
+-----------------------------------------
+
+Since a large number of different Linux distributions are 
+available, we are unable to describe a general installation procedure
+for the driver module.
+Because the driver is now integrated in the kernel, installation should
+be easy, using the standard mechanism of your distribution.
+Refer to the distribution's manual for installation of ethernet adapters.
+
+***
+
+4  Driver Parameters
+====================
+
+Parameters can be set at the command line after the module has been 
+loaded with the command 'modprobe'.
+In some distributions, the configuration tools are able to pass parameters
+to the driver module.
+
+If you use the kernel module loader, you can set driver parameters
+in the file /etc/modprobe.conf (or /etc/modules.conf in 2.4 or earlier).
+To set the driver parameters in this file, proceed as follows:
+
+1. Insert a line of the form :
+   options sk98lin ...
+   For "...", the same syntax is required as described for the command
+   line parameters of modprobe below.
+2. To activate the new parameters, either reboot your computer
+   or 
+   unload and reload the driver.
+   The syntax of the driver parameters is:
+
+        modprobe sk98lin parameter=value1[,value2[,value3...]]
+
+   where value1 refers to the first adapter, value2 to the second etc.
+
+NOTE: All parameters are case sensitive. Write them exactly as shown 
+      below.
+
+Example:
+Suppose you have two adapters. You want to set auto-negotiation
+on the first adapter to ON and on the second adapter to OFF.
+You also want to set DuplexCapabilities on the first adapter
+to FULL, and on the second adapter to HALF.
+Then, you must enter:
+
+        modprobe sk98lin AutoNeg_A=On,Off DupCap_A=Full,Half
+
+NOTE: The number of adapters that can be configured this way is
+      limited in the driver (file skge.c, constant SK_MAX_CARD_PARAM).
+      The current limit is 16. If you happen to install
+      more adapters, adjust this and recompile.
+
+
+4.1  Per-Port Parameters
+------------------------
+
+These settings are available for each port on the adapter.
+In the following description, '?' stands for the port for
+which you set the parameter (A or B).
+
+Speed
+-----
+Parameter:    Speed_?
+Values:       10, 100, 1000, Auto
+Default:      Auto
+
+This parameter is used to set the speed capabilities. It is only valid 
+for the SK-98xx V2.0 copper adapters.
+Usually, the speed is negotiated between the two ports during link 
+establishment. If this fails, a port can be forced to a specific setting
+with this parameter.
+
+Auto-Negotiation
+----------------
+Parameter:    AutoNeg_?
+Values:       On, Off, Sense
+Default:      On
+  
+The "Sense"-mode automatically detects whether the link partner supports
+auto-negotiation or not.
+
+Duplex Capabilities
+-------------------
+Parameter:    DupCap_?
+Values:       Half, Full, Both
+Default:      Both
+
+This parameters is only relevant if auto-negotiation for this port is 
+not set to "Sense". If auto-negotiation is set to "On", all three values
+are possible. If it is set to "Off", only "Full" and "Half" are allowed.
+This parameter is useful if your link partner does not support all
+possible combinations.
+
+Flow Control
+------------
+Parameter:    FlowCtrl_?
+Values:       Sym, SymOrRem, LocSend, None
+Default:      SymOrRem
+
+This parameter can be used to set the flow control capabilities the 
+port reports during auto-negotiation. It can be set for each port 
+individually.
+Possible modes:
+   -- Sym      = Symmetric: both link partners are allowed to send 
+                  PAUSE frames
+   -- SymOrRem = SymmetricOrRemote: both or only remote partner 
+                  are allowed to send PAUSE frames
+   -- LocSend  = LocalSend: only local link partner is allowed 
+                  to send PAUSE frames
+   -- None     = no link partner is allowed to send PAUSE frames
+  
+NOTE: This parameter is ignored if auto-negotiation is set to "Off".
+
+Role in Master-Slave-Negotiation (1000Base-T only)
+--------------------------------------------------
+Parameter:    Role_?
+Values:       Auto, Master, Slave
+Default:      Auto
+
+This parameter is only valid for the SK-9821 and SK-9822 adapters.
+For two 1000Base-T ports to communicate, one must take the role of the
+master (providing timing information), while the other must be the 
+slave. Usually, this is negotiated between the two ports during link 
+establishment. If this fails, a port can be forced to a specific setting
+with this parameter.
+
+
+4.2  Adapter Parameters
+-----------------------
+
+Connection Type (SK-98xx V2.0 copper adapters only)
+---------------
+Parameter:    ConType
+Values:       Auto, 100FD, 100HD, 10FD, 10HD
+Default:      Auto
+
+The parameter 'ConType' is a combination of all five per-port parameters
+within one single parameter. This simplifies the configuration of both ports
+of an adapter card! The different values of this variable reflect the most 
+meaningful combinations of port parameters.
+
+The following table shows the values of 'ConType' and the corresponding
+combinations of the per-port parameters:
+
+    ConType   |  DupCap   AutoNeg   FlowCtrl   Role             Speed
+    ----------+------------------------------------------------------
+    Auto      |  Both     On        SymOrRem   Auto             Auto
+    100FD     |  Full     Off       None       Auto (ignored)   100
+    100HD     |  Half     Off       None       Auto (ignored)   100
+    10FD      |  Full     Off       None       Auto (ignored)   10
+    10HD      |  Half     Off       None       Auto (ignored)   10
+
+Stating any other port parameter together with this 'ConType' variable
+will result in a merged configuration of those settings. This due to 
+the fact, that the per-port parameters (e.g. Speed_? ) have a higher
+priority than the combined variable 'ConType'.
+
+NOTE: This parameter is always used on both ports of the adapter card.
+
+Interrupt Moderation
+--------------------
+Parameter:    Moderation
+Values:       None, Static, Dynamic
+Default:      None
+
+Interrupt moderation is employed to limit the maximum number of interrupts
+the driver has to serve. That is, one or more interrupts (which indicate any
+transmit or receive packet to be processed) are queued until the driver 
+processes them. When queued interrupts are to be served, is determined by the
+'IntsPerSec' parameter, which is explained later below.
+
+Possible modes:
+
+   -- None - No interrupt moderation is applied on the adapter card. 
+      Therefore, each transmit or receive interrupt is served immediately
+      as soon as it appears on the interrupt line of the adapter card.
+
+   -- Static - Interrupt moderation is applied on the adapter card. 
+      All transmit and receive interrupts are queued until a complete
+      moderation interval ends. If such a moderation interval ends, all
+      queued interrupts are processed in one big bunch without any delay.
+      The term 'static' reflects the fact, that interrupt moderation is
+      always enabled, regardless how much network load is currently 
+      passing via a particular interface. In addition, the duration of
+      the moderation interval has a fixed length that never changes while
+      the driver is operational.
+
+   -- Dynamic - Interrupt moderation might be applied on the adapter card,
+      depending on the load of the system. If the driver detects that the
+      system load is too high, the driver tries to shield the system against 
+      too much network load by enabling interrupt moderation. If - at a later
+      time - the CPU utilization decreases again (or if the network load is 
+      negligible) the interrupt moderation will automatically be disabled.
+
+Interrupt moderation should be used when the driver has to handle one or more
+interfaces with a high network load, which - as a consequence - leads also to a
+high CPU utilization. When moderation is applied in such high network load 
+situations, CPU load might be reduced by 20-30%.
+
+NOTE: The drawback of using interrupt moderation is an increase of the round-
+trip-time (RTT), due to the queueing and serving of interrupts at dedicated
+moderation times.
+
+Interrupts per second
+---------------------
+Parameter:    IntsPerSec
+Values:       30...40000 (interrupts per second)
+Default:      2000
+
+This parameter is only used if either static or dynamic interrupt moderation
+is used on a network adapter card. Using this parameter if no moderation is
+applied will lead to no action performed.
+
+This parameter determines the length of any interrupt moderation interval. 
+Assuming that static interrupt moderation is to be used, an 'IntsPerSec' 
+parameter value of 2000 will lead to an interrupt moderation interval of
+500 microseconds. 
+
+NOTE: The duration of the moderation interval is to be chosen with care.
+At first glance, selecting a very long duration (e.g. only 100 interrupts per 
+second) seems to be meaningful, but the increase of packet-processing delay 
+is tremendous. On the other hand, selecting a very short moderation time might
+compensate the use of any moderation being applied.
+
+
+Preferred Port
+--------------
+Parameter:    PrefPort
+Values:       A, B
+Default:      A
+
+This is used to force the preferred port to A or B (on dual-port network 
+adapters). The preferred port is the one that is used if both are detected
+as fully functional.
+
+RLMT Mode (Redundant Link Management Technology)
+------------------------------------------------
+Parameter:    RlmtMode
+Values:       CheckLinkState,CheckLocalPort, CheckSeg, DualNet
+Default:      CheckLinkState
+
+RLMT monitors the status of the port. If the link of the active port 
+fails, RLMT switches immediately to the standby link. The virtual link is 
+maintained as long as at least one 'physical' link is up. 
+
+Possible modes:
+
+   -- CheckLinkState - Check link state only: RLMT uses the link state
+      reported by the adapter hardware for each individual port to 
+      determine whether a port can be used for all network traffic or 
+      not.
+
+   -- CheckLocalPort - In this mode, RLMT monitors the network path 
+      between the two ports of an adapter by regularly exchanging packets
+      between them. This mode requires a network configuration in which 
+      the two ports are able to "see" each other (i.e. there must not be 
+      any router between the ports).
+
+   -- CheckSeg - Check local port and segmentation: This mode supports the
+      same functions as the CheckLocalPort mode and additionally checks 
+      network segmentation between the ports. Therefore, this mode is only
+      to be used if Gigabit Ethernet switches are installed on the network
+      that have been configured to use the Spanning Tree protocol. 
+
+   -- DualNet - In this mode, ports A and B are used as separate devices. 
+      If you have a dual port adapter, port A will be configured as eth0 
+      and port B as eth1. Both ports can be used independently with 
+      distinct IP addresses. The preferred port setting is not used. 
+      RLMT is turned off.
+   
+NOTE: RLMT modes CLP and CLPSS are designed to operate in configurations 
+      where a network path between the ports on one adapter exists. 
+      Moreover, they are not designed to work where adapters are connected
+      back-to-back.
+***
+
+
+5  Large Frame Support
+======================
+
+The driver supports large frames (also called jumbo frames). Using large 
+frames can result in an improved throughput if transferring large amounts 
+of data.
+To enable large frames, set the MTU (maximum transfer unit) of the 
+interface to the desired value (up to 9000), execute the following 
+command:
+      ifconfig eth0 mtu 9000
+This will only work if you have two adapters connected back-to-back
+or if you use a switch that supports large frames. When using a switch, 
+it should be configured to allow large frames and auto-negotiation should  
+be set to OFF. The setting must be configured on all adapters that can be 
+reached by the large frames. If one adapter is not set to receive large 
+frames, it will simply drop them.
+
+You can switch back to the standard ethernet frame size by executing the 
+following command:
+      ifconfig eth0 mtu 1500
+
+To permanently configure this setting, add a script with the 'ifconfig' 
+line to the system startup sequence (named something like "S99sk98lin" 
+in /etc/rc.d/rc2.d).
+***
+
+
+6  VLAN and Link Aggregation Support (IEEE 802.1, 802.1q, 802.3ad)
+==================================================================
+
+The Marvell Yukon/SysKonnect Linux drivers are able to support VLAN and 
+Link Aggregation according to IEEE standards 802.1, 802.1q, and 802.3ad. 
+These features are only available after installation of open source 
+modules available on the Internet:
+For VLAN go to: http://www.candelatech.com/~greear/vlan.html
+For Link Aggregation go to: http://www.st.rim.or.jp/~yumo
+
+NOTE: SysKonnect GmbH does not offer any support for these open source 
+      modules and does not take the responsibility for any kind of 
+      failures or problems arising in connection with these modules.
+
+NOTE: Configuring Link Aggregation on a SysKonnect dual link adapter may 
+      cause problems when unloading the driver.
+
+
+7  Troubleshooting
+==================
+
+If any problems occur during the installation process, check the 
+following list:
+
+
+Problem:  The SK-98xx adapter cannot be found by the driver.
+Solution: In /proc/pci search for the following entry:
+             'Ethernet controller: SysKonnect SK-98xx ...'
+          If this entry exists, the SK-98xx or SK-98xx V2.0 adapter has 
+          been found by the system and should be operational.
+          If this entry does not exist or if the file '/proc/pci' is not 
+          found, there may be a hardware problem or the PCI support may 
+          not be enabled in your kernel.
+          The adapter can be checked using the diagnostics program which 
+          is available on the SysKonnect web site:
+          www.syskonnect.com
+          
+          Some COMPAQ machines have problems dealing with PCI under Linux.
+          This problem is described in the 'PCI howto' document
+          (included in some distributions or available from the
+          web, e.g. at 'www.linux.org'). 
+
+
+Problem:  Programs such as 'ifconfig' or 'route' cannot be found or the 
+          error message 'Operation not permitted' is displayed.
+Reason:   You are not logged in as user 'root'.
+Solution: Logout and login as 'root' or change to 'root' via 'su'.
+
+
+Problem:  Upon use of the command 'ping <address>' the message
+          "ping: sendto: Network is unreachable" is displayed.
+Reason:   Your route is not set correctly.
+Solution: If you are using RedHat, you probably forgot to set up the 
+          route in the 'network configuration'.
+          Check the existing routes with the 'route' command and check 
+          if an entry for 'eth0' exists, and if so, if it is set correctly.
+
+
+Problem:  The driver can be started, the adapter is connected to the 
+          network, but you cannot receive or transmit any packets; 
+          e.g. 'ping' does not work.
+Reason:   There is an incorrect route in your routing table.
+Solution: Check the routing table with the command 'route' and read the 
+          manual help pages dealing with routes (enter 'man route').
+
+NOTE: Although the 2.2.x kernel versions generate the routing entry 
+      automatically, problems of this kind may occur here as well. We've 
+      come across a situation in which the driver started correctly at 
+      system start, but after the driver has been removed and reloaded,
+      the route of the adapter's network pointed to the 'dummy0'device 
+      and had to be corrected manually.
+
+
+Problem:  Your computer should act as a router between multiple 
+          IP subnetworks (using multiple adapters), but computers in 
+          other subnetworks cannot be reached.
+Reason:   Either the router's kernel is not configured for IP forwarding 
+          or the routing table and gateway configuration of at least one 
+          computer is not working.
+
+Problem:  Upon driver start, the following error message is displayed:
+          "eth0: -- ERROR --
+          Class: internal Software error
+          Nr:    0xcc
+          Msg:   SkGeInitPort() cannot init running ports"
+Reason:   You are using a driver compiled for single processor machines 
+          on a multiprocessor machine with SMP (Symmetric MultiProcessor) 
+          kernel.
+Solution: Configure your kernel appropriately and recompile the kernel or
+          the modules.
+
+
+
+If your problem is not listed here, please contact SysKonnect's technical
+support for help (linux@syskonnect.de).
+When contacting our technical support, please ensure that the following 
+information is available:
+- System Manufacturer and HW Informations (CPU, Memory... )
+- PCI-Boards in your system
+- Distribution
+- Kernel version
+- Driver version
+***
+
+
+
+***End of Readme File***
index 5b9e17b..c551925 100644 (file)
@@ -2177,7 +2177,7 @@ config SKGE
          with better performance and more complete ethtool support.
 
          It does not support the link failover and network management 
-         features available in the hardware.
+         features that "portable" vendor supplied sk98lin driver does.
 
          This driver supports adapters based on the original Yukon chipset:
          Marvell 88E8001, Belkin F5D5005, CNet GigaCard, DLink DGE-530T,
@@ -2215,6 +2215,93 @@ config SKY2_DEBUG
 
         If unsure, say N.
 
+config SK98LIN
+       tristate "Marvell Yukon Chipset / SysKonnect SK-98xx Support (DEPRECATED)"
+       depends on PCI
+       ---help---
+         Say Y here if you have a Marvell Yukon or SysKonnect SK-98xx/SK-95xx
+         compliant Gigabit Ethernet Adapter.
+
+         This driver supports the original Yukon chipset. This driver is
+         deprecated and will be removed from the kernel in the near future,
+         it has been replaced by the skge driver. skge is cleaner and
+         seems to work better.
+
+         This driver does not support the newer Yukon2 chipset. A separate
+         driver, sky2, is provided to support Yukon2-based adapters.
+
+         The following adapters are supported by this driver:
+           - 3Com 3C940 Gigabit LOM Ethernet Adapter
+           - 3Com 3C941 Gigabit LOM Ethernet Adapter
+           - Allied Telesyn AT-2970LX Gigabit Ethernet Adapter
+           - Allied Telesyn AT-2970LX/2SC Gigabit Ethernet Adapter
+           - Allied Telesyn AT-2970SX Gigabit Ethernet Adapter
+           - Allied Telesyn AT-2970SX/2SC Gigabit Ethernet Adapter
+           - Allied Telesyn AT-2970TX Gigabit Ethernet Adapter
+           - Allied Telesyn AT-2970TX/2TX Gigabit Ethernet Adapter
+           - Allied Telesyn AT-2971SX Gigabit Ethernet Adapter
+           - Allied Telesyn AT-2971T Gigabit Ethernet Adapter
+           - Belkin Gigabit Desktop Card 10/100/1000Base-T Adapter, Copper RJ-45
+           - EG1032 v2 Instant Gigabit Network Adapter
+           - EG1064 v2 Instant Gigabit Network Adapter
+           - Marvell 88E8001 Gigabit LOM Ethernet Adapter (Abit)
+           - Marvell 88E8001 Gigabit LOM Ethernet Adapter (Albatron)
+           - Marvell 88E8001 Gigabit LOM Ethernet Adapter (Asus)
+           - Marvell 88E8001 Gigabit LOM Ethernet Adapter (ECS)
+           - Marvell 88E8001 Gigabit LOM Ethernet Adapter (Epox)
+           - Marvell 88E8001 Gigabit LOM Ethernet Adapter (Foxconn)
+           - Marvell 88E8001 Gigabit LOM Ethernet Adapter (Gigabyte)
+           - Marvell 88E8001 Gigabit LOM Ethernet Adapter (Iwill)
+           - Marvell 88E8050 Gigabit LOM Ethernet Adapter (Intel)
+           - Marvell RDK-8001 Adapter
+           - Marvell RDK-8002 Adapter
+           - Marvell RDK-8003 Adapter
+           - Marvell RDK-8004 Adapter
+           - Marvell RDK-8006 Adapter
+           - Marvell RDK-8007 Adapter
+           - Marvell RDK-8008 Adapter
+           - Marvell RDK-8009 Adapter
+           - Marvell RDK-8010 Adapter
+           - Marvell RDK-8011 Adapter
+           - Marvell RDK-8012 Adapter
+           - Marvell RDK-8052 Adapter
+           - Marvell Yukon Gigabit Ethernet 10/100/1000Base-T Adapter (32 bit)
+           - Marvell Yukon Gigabit Ethernet 10/100/1000Base-T Adapter (64 bit)
+           - N-Way PCI-Bus Giga-Card 1000/100/10Mbps(L)
+           - SK-9521 10/100/1000Base-T Adapter
+           - SK-9521 V2.0 10/100/1000Base-T Adapter
+           - SK-9821 Gigabit Ethernet Server Adapter (SK-NET GE-T)
+           - SK-9821 V2.0 Gigabit Ethernet 10/100/1000Base-T Adapter
+           - SK-9822 Gigabit Ethernet Server Adapter (SK-NET GE-T dual link)
+           - SK-9841 Gigabit Ethernet Server Adapter (SK-NET GE-LX)
+           - SK-9841 V2.0 Gigabit Ethernet 1000Base-LX Adapter
+           - SK-9842 Gigabit Ethernet Server Adapter (SK-NET GE-LX dual link)
+           - SK-9843 Gigabit Ethernet Server Adapter (SK-NET GE-SX)
+           - SK-9843 V2.0 Gigabit Ethernet 1000Base-SX Adapter
+           - SK-9844 Gigabit Ethernet Server Adapter (SK-NET GE-SX dual link)
+           - SK-9851 V2.0 Gigabit Ethernet 1000Base-SX Adapter
+           - SK-9861 Gigabit Ethernet Server Adapter (SK-NET GE-SX Volition)
+           - SK-9861 V2.0 Gigabit Ethernet 1000Base-SX Adapter
+           - SK-9862 Gigabit Ethernet Server Adapter (SK-NET GE-SX Volition dual link)
+           - SK-9871 Gigabit Ethernet Server Adapter (SK-NET GE-ZX)
+           - SK-9871 V2.0 Gigabit Ethernet 1000Base-ZX Adapter
+           - SK-9872 Gigabit Ethernet Server Adapter (SK-NET GE-ZX dual link)
+           - SMC EZ Card 1000 (SMC9452TXV.2)
+         
+         The adapters support Jumbo Frames.
+         The dual link adapters support link-failover and dual port features.
+         Both Marvell Yukon and SysKonnect SK-98xx/SK-95xx adapters support 
+         the scatter-gather functionality with sendfile(). Please refer to 
+         <file:Documentation/networking/sk98lin.txt> for more information about
+         optional driver parameters.
+         Questions concerning this driver may be addressed to:
+             <linux@syskonnect.de>
+         
+         If you want to compile this driver as a module ( = code which can be
+         inserted in and removed from the running kernel whenever you want),
+         say M here and read <file:Documentation/kbuild/modules.txt>. The module will
+         be called sk98lin. This is recommended.
+
 config VIA_VELOCITY
        tristate "VIA Velocity support"
        depends on PCI
index e684212..9c928a8 100644 (file)
@@ -66,6 +66,7 @@ ps3_gelic-objs += ps3_gelic_net.o
 obj-$(CONFIG_TC35815) += tc35815.o
 obj-$(CONFIG_SKGE) += skge.o
 obj-$(CONFIG_SKY2) += sky2.o
+obj-$(CONFIG_SK98LIN) += sk98lin/
 obj-$(CONFIG_SKFP) += skfp/
 obj-$(CONFIG_VIA_RHINE) += via-rhine.o
 obj-$(CONFIG_VIA_VELOCITY) += via-velocity.o
diff --git a/drivers/net/sk98lin/Makefile b/drivers/net/sk98lin/Makefile
new file mode 100644 (file)
index 0000000..afd900d
--- /dev/null
@@ -0,0 +1,87 @@
+#
+# Makefile for the SysKonnect SK-98xx device driver.
+#
+
+
+#
+# Standalone driver params
+# SKPARAM += -DSK_KERNEL_24
+# SKPARAM += -DSK_KERNEL_24_26
+# SKPARAM += -DSK_KERNEL_26
+# SKPARAM += -DSK_KERNEL_22_24
+
+obj-$(CONFIG_SK98LIN) += sk98lin.o
+sk98lin-objs    :=     \
+               skge.o          \
+               skethtool.o     \
+               skdim.o         \
+               skaddr.o        \
+               skgehwt.o       \
+               skgeinit.o      \
+               skgepnmi.o      \
+               skgesirq.o      \
+               ski2c.o         \
+               sklm80.o        \
+               skqueue.o       \
+               skrlmt.o        \
+               sktimer.o       \
+               skvpd.o         \
+               skxmac2.o
+
+# DBGDEF =  \
+# -DDEBUG
+
+ifdef DEBUG
+DBGDEF +=  \
+-DSK_DEBUG_CHKMOD=0x00000000L \
+-DSK_DEBUG_CHKCAT=0x00000000L
+endif
+
+
+# **** possible debug modules for SK_DEBUG_CHKMOD *****************
+# SK_DBGMOD_MERR        0x00000001L     /* general module error indication */
+# SK_DBGMOD_HWM         0x00000002L     /* Hardware init module */
+# SK_DBGMOD_RLMT        0x00000004L     /* RLMT module */
+# SK_DBGMOD_VPD         0x00000008L     /* VPD module */
+# SK_DBGMOD_I2C         0x00000010L     /* I2C module */
+# SK_DBGMOD_PNMI        0x00000020L     /* PNMI module */
+# SK_DBGMOD_CSUM        0x00000040L     /* CSUM module */
+# SK_DBGMOD_ADDR        0x00000080L     /* ADDR module */
+# SK_DBGMOD_DRV         0x00010000L     /* DRV module */
+
+# **** possible debug categories for SK_DEBUG_CHKCAT **************
+# *** common modules ***
+# SK_DBGCAT_INIT        0x00000001L     module/driver initialization
+# SK_DBGCAT_CTRL        0x00000002L     controlling: add/rmv MCA/MAC and other controls (IOCTL)
+# SK_DBGCAT_ERR         0x00000004L     error handling paths
+# SK_DBGCAT_TX          0x00000008L     transmit path
+# SK_DBGCAT_RX          0x00000010L     receive path
+# SK_DBGCAT_IRQ         0x00000020L     general IRQ handling
+# SK_DBGCAT_QUEUE       0x00000040L     any queue management
+# SK_DBGCAT_DUMP        0x00000080L     large data output e.g. hex dump
+# SK_DBGCAT_FATAL       0x00000100L     large data output e.g. hex dump
+
+# *** driver (file skge.c) ***
+# SK_DBGCAT_DRV_ENTRY           0x00010000      entry points
+# SK_DBGCAT_DRV_???             0x00020000      not used
+# SK_DBGCAT_DRV_MCA             0x00040000      multicast
+# SK_DBGCAT_DRV_TX_PROGRESS     0x00080000      tx path
+# SK_DBGCAT_DRV_RX_PROGRESS     0x00100000      rx path
+# SK_DBGCAT_DRV_PROGRESS        0x00200000      general runtime
+# SK_DBGCAT_DRV_???             0x00400000      not used
+# SK_DBGCAT_DRV_PROM            0x00800000      promiscuous mode
+# SK_DBGCAT_DRV_TX_FRAME        0x01000000      display tx frames
+# SK_DBGCAT_DRV_ERROR           0x02000000      error conditions
+# SK_DBGCAT_DRV_INT_SRC         0x04000000      interrupts sources
+# SK_DBGCAT_DRV_EVENT           0x08000000      driver events
+
+EXTRA_CFLAGS += -Idrivers/net/sk98lin -DSK_DIAG_SUPPORT -DGENESIS -DYUKON $(DBGDEF) $(SKPARAM)
+
+clean:
+       rm -f core *.o *.a *.s
+
+
+
+
+
+
diff --git a/drivers/net/sk98lin/h/lm80.h b/drivers/net/sk98lin/h/lm80.h
new file mode 100644 (file)
index 0000000..4e2dbbf
--- /dev/null
@@ -0,0 +1,179 @@
+/******************************************************************************
+ *
+ * Name:       lm80.h  
+ * Project:    Gigabit Ethernet Adapters, Common Modules
+ * Version:    $Revision: 1.6 $
+ * Date:       $Date: 2003/05/13 17:26:52 $
+ * Purpose:    Contains all defines for the LM80 Chip
+ *             (National Semiconductor).
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *     (C)Copyright 1998-2002 SysKonnect.
+ *     (C)Copyright 2002-2003 Marvell.
+ *
+ *     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.
+ *
+ *     The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+#ifndef __INC_LM80_H
+#define __INC_LM80_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/* defines ********************************************************************/
+
+/*
+ * LM80 register definition
+ *
+ * All registers are 8 bit wide
+ */
+#define LM80_CFG                       0x00    /* Configuration Register */
+#define LM80_ISRC_1                    0x01    /* Interrupt Status Register 1 */
+#define LM80_ISRC_2                    0x02    /* Interrupt Status Register 2 */
+#define LM80_IMSK_1                    0x03    /* Interrupt Mask Register 1 */
+#define LM80_IMSK_2                    0x04    /* Interrupt Mask Register 2 */
+#define LM80_FAN_CTRL          0x05    /* Fan Devisor/RST#/OS# Register */
+#define LM80_TEMP_CTRL         0x06    /* OS# Config, Temp Res. Reg */
+       /* 0x07 - 0x1f reserved */
+       /* current values */
+#define LM80_VT0_IN                    0x20    /* current Voltage 0 value */
+#define LM80_VT1_IN                    0x21    /* current Voltage 1 value */
+#define LM80_VT2_IN                    0x22    /* current Voltage 2 value */
+#define LM80_VT3_IN                    0x23    /* current Voltage 3 value */
+#define LM80_VT4_IN                    0x24    /* current Voltage 4 value */
+#define LM80_VT5_IN                    0x25    /* current Voltage 5 value */
+#define LM80_VT6_IN                    0x26    /* current Voltage 6 value */
+#define LM80_TEMP_IN           0x27    /* current Temperature value */
+#define LM80_FAN1_IN           0x28    /* current Fan 1 count */
+#define LM80_FAN2_IN           0x29    /* current Fan 2 count */
+       /* limit values */
+#define LM80_VT0_HIGH_LIM      0x2a    /* high limit val for Voltage 0 */
+#define LM80_VT0_LOW_LIM       0x2b    /* low limit val for Voltage 0 */
+#define LM80_VT1_HIGH_LIM      0x2c    /* high limit val for Voltage 1 */
+#define LM80_VT1_LOW_LIM       0x2d    /* low limit val for Voltage 1 */
+#define LM80_VT2_HIGH_LIM      0x2e    /* high limit val for Voltage 2 */
+#define LM80_VT2_LOW_LIM       0x2f    /* low limit val for Voltage 2 */
+#define LM80_VT3_HIGH_LIM      0x30    /* high limit val for Voltage 3 */
+#define LM80_VT3_LOW_LIM       0x31    /* low limit val for Voltage 3 */
+#define LM80_VT4_HIGH_LIM      0x32    /* high limit val for Voltage 4 */
+#define LM80_VT4_LOW_LIM       0x33    /* low limit val for Voltage 4 */
+#define LM80_VT5_HIGH_LIM      0x34    /* high limit val for Voltage 5 */
+#define LM80_VT5_LOW_LIM       0x35    /* low limit val for Voltage 5 */
+#define LM80_VT6_HIGH_LIM      0x36    /* high limit val for Voltage 6 */
+#define LM80_VT6_LOW_LIM       0x37    /* low limit val for Voltage 6 */
+#define LM80_THOT_LIM_UP       0x38    /* hot temperature limit (high) */
+#define LM80_THOT_LIM_LO       0x39    /* hot temperature limit (low) */
+#define LM80_TOS_LIM_UP                0x3a    /* OS temperature limit (high) */
+#define LM80_TOS_LIM_LO                0x3b    /* OS temperature limit (low) */
+#define LM80_FAN1_COUNT_LIM    0x3c    /* Fan 1 count limit (high) */
+#define LM80_FAN2_COUNT_LIM    0x3d    /* Fan 2 count limit (low) */
+       /* 0x3e - 0x3f reserved */
+
+/*
+ * LM80 bit definitions
+ */
+
+/*     LM80_CFG                Configuration Register */
+#define LM80_CFG_START         (1<<0)  /* start monitoring operation */
+#define LM80_CFG_INT_ENA       (1<<1)  /* enables the INT# Interrupt output */
+#define LM80_CFG_INT_POL       (1<<2)  /* INT# pol: 0 act low, 1 act high */
+#define LM80_CFG_INT_CLR       (1<<3)  /* disables INT#/RST_OUT#/OS# outputs */
+#define LM80_CFG_RESET         (1<<4)  /* signals a reset */
+#define LM80_CFG_CHASS_CLR     (1<<5)  /* clears Chassis Intrusion (CI) pin */
+#define LM80_CFG_GPO           (1<<6)  /* drives the GPO# pin */
+#define LM80_CFG_INIT          (1<<7)  /* restore power on defaults */
+
+/*     LM80_ISRC_1             Interrupt Status Register 1 */
+/*     LM80_IMSK_1             Interrupt Mask Register 1 */
+#define LM80_IS_VT0                    (1<<0)  /* limit exceeded for Voltage 0 */
+#define LM80_IS_VT1                    (1<<1)  /* limit exceeded for Voltage 1 */
+#define LM80_IS_VT2                    (1<<2)  /* limit exceeded for Voltage 2 */
+#define LM80_IS_VT3                    (1<<3)  /* limit exceeded for Voltage 3 */
+#define LM80_IS_VT4                    (1<<4)  /* limit exceeded for Voltage 4 */
+#define LM80_IS_VT5                    (1<<5)  /* limit exceeded for Voltage 5 */
+#define LM80_IS_VT6                    (1<<6)  /* limit exceeded for Voltage 6 */
+#define LM80_IS_INT_IN         (1<<7)  /* state of INT_IN# */
+
+/*     LM80_ISRC_2             Interrupt Status Register 2 */
+/*     LM80_IMSK_2             Interrupt Mask Register 2 */
+#define LM80_IS_TEMP           (1<<0)  /* HOT temperature limit exceeded */
+#define LM80_IS_BTI                    (1<<1)  /* state of BTI# pin */
+#define LM80_IS_FAN1           (1<<2)  /* count limit exceeded for Fan 1 */
+#define LM80_IS_FAN2           (1<<3)  /* count limit exceeded for Fan 2 */
+#define LM80_IS_CI                     (1<<4)  /* Chassis Intrusion occured */
+#define LM80_IS_OS                     (1<<5)  /* OS temperature limit exceeded */
+       /* bit 6 and 7 are reserved in LM80_ISRC_2 */
+#define LM80_IS_HT_IRQ_MD      (1<<6)  /* Hot temperature interrupt mode */
+#define LM80_IS_OT_IRQ_MD      (1<<7)  /* OS temperature interrupt mode */
+
+/*     LM80_FAN_CTRL           Fan Devisor/RST#/OS# Register */
+#define LM80_FAN1_MD_SEL       (1<<0)  /* Fan 1 mode select */
+#define LM80_FAN2_MD_SEL       (1<<1)  /* Fan 2 mode select */
+#define LM80_FAN1_PRM_CTL      (3<<2)  /* Fan 1 speed control */
+#define LM80_FAN2_PRM_CTL      (3<<4)  /* Fan 2 speed control */
+#define LM80_FAN_OS_ENA                (1<<6)  /* enable OS mode on RST_OUT#/OS# pins*/
+#define LM80_FAN_RST_ENA       (1<<7)  /* sets RST_OUT#/OS# pins in RST mode */
+
+/*     LM80_TEMP_CTRL          OS# Config, Temp Res. Reg */
+#define LM80_TEMP_OS_STAT      (1<<0)  /* mirrors the state of RST_OUT#/OS# */
+#define LM80_TEMP_OS_POL       (1<<1)  /* select OS# polarity */
+#define LM80_TEMP_OS_MODE      (1<<2)  /* selects Interrupt mode */
+#define LM80_TEMP_RES          (1<<3)  /* selects 9 or 11 bit temp resulution*/
+#define LM80_TEMP_LSB          (0xf<<4)/* 4 LSBs of 11 bit temp data */
+#define LM80_TEMP_LSB_9                (1<<7)  /* LSB of 9 bit temperature data */
+
+       /* 0x07 - 0x1f reserved */
+/*     LM80_VT0_IN             current Voltage 0 value */
+/*     LM80_VT1_IN             current Voltage 1 value */
+/*     LM80_VT2_IN             current Voltage 2 value */
+/*     LM80_VT3_IN             current Voltage 3 value */
+/*     LM80_VT4_IN             current Voltage 4 value */
+/*     LM80_VT5_IN             current Voltage 5 value */
+/*     LM80_VT6_IN             current Voltage 6 value */
+/*     LM80_TEMP_IN            current temperature value */
+/*     LM80_FAN1_IN            current Fan 1 count */
+/*     LM80_FAN2_IN            current Fan 2 count */
+/*     LM80_VT0_HIGH_LIM       high limit val for Voltage 0 */
+/*     LM80_VT0_LOW_LIM        low limit val for Voltage 0 */
+/*     LM80_VT1_HIGH_LIM       high limit val for Voltage 1 */
+/*     LM80_VT1_LOW_LIM        low limit val for Voltage 1 */
+/*     LM80_VT2_HIGH_LIM       high limit val for Voltage 2 */
+/*     LM80_VT2_LOW_LIM        low limit val for Voltage 2 */
+/*     LM80_VT3_HIGH_LIM       high limit val for Voltage 3 */
+/*     LM80_VT3_LOW_LIM        low limit val for Voltage 3 */
+/*     LM80_VT4_HIGH_LIM       high limit val for Voltage 4 */
+/*     LM80_VT4_LOW_LIM        low limit val for Voltage 4 */
+/*     LM80_VT5_HIGH_LIM       high limit val for Voltage 5 */
+/*     LM80_VT5_LOW_LIM        low limit val for Voltage 5 */
+/*     LM80_VT6_HIGH_LIM       high limit val for Voltage 6 */
+/*     LM80_VT6_LOW_LIM        low limit val for Voltage 6 */
+/*     LM80_THOT_LIM_UP        hot temperature limit (high) */
+/*     LM80_THOT_LIM_LO        hot temperature limit (low) */
+/*     LM80_TOS_LIM_UP         OS temperature limit (high) */
+/*     LM80_TOS_LIM_LO         OS temperature limit (low) */
+/*     LM80_FAN1_COUNT_LIM     Fan 1 count limit (high) */
+/*     LM80_FAN2_COUNT_LIM     Fan 2 count limit (low) */
+       /* 0x3e - 0x3f reserved */
+
+#define LM80_ADDR              0x28    /* LM80 default addr */
+
+/* typedefs *******************************************************************/
+
+
+/* function prototypes ********************************************************/
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __INC_LM80_H */
diff --git a/drivers/net/sk98lin/h/skaddr.h b/drivers/net/sk98lin/h/skaddr.h
new file mode 100644 (file)
index 0000000..423ad06
--- /dev/null
@@ -0,0 +1,285 @@
+/******************************************************************************
+ *
+ * Name:       skaddr.h
+ * Project:    Gigabit Ethernet Adapters, ADDR-Modul
+ * Version:    $Revision: 1.29 $
+ * Date:       $Date: 2003/05/13 16:57:24 $
+ * Purpose:    Header file for Address Management (MC, UC, Prom).
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *     (C)Copyright 1998-2002 SysKonnect GmbH.
+ *     (C)Copyright 2002-2003 Marvell.
+ *
+ *     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.
+ *
+ *     The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * Description:
+ *
+ * This module is intended to manage multicast addresses and promiscuous mode
+ * on GEnesis adapters.
+ *
+ * Include File Hierarchy:
+ *
+ *     "skdrv1st.h"
+ *     ...
+ *     "sktypes.h"
+ *     "skqueue.h"
+ *     "skaddr.h"
+ *     ...
+ *     "skdrv2nd.h"
+ *
+ ******************************************************************************/
+
+#ifndef __INC_SKADDR_H
+#define __INC_SKADDR_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* cplusplus */
+
+/* defines ********************************************************************/
+
+#define SK_MAC_ADDR_LEN                                6       /* Length of MAC address. */
+#define        SK_MAX_ADDRS                            14      /* #Addrs for exact match. */
+
+/* ----- Common return values ----- */
+
+#define SK_ADDR_SUCCESS                                0       /* Function returned successfully. */
+#define SK_ADDR_ILLEGAL_PORT                   100     /* Port number too high. */
+#define SK_ADDR_TOO_EARLY                      101     /* Function called too early. */
+
+/* ----- Clear/Add flag bits ----- */
+
+#define SK_ADDR_PERMANENT                      1       /* RLMT Address */
+
+/* ----- Additional Clear flag bits ----- */
+
+#define SK_MC_SW_ONLY                          2       /* Do not update HW when clearing. */
+
+/* ----- Override flag bits ----- */
+
+#define SK_ADDR_LOGICAL_ADDRESS                0
+#define SK_ADDR_VIRTUAL_ADDRESS                (SK_ADDR_LOGICAL_ADDRESS)       /* old */
+#define SK_ADDR_PHYSICAL_ADDRESS       1
+#define SK_ADDR_CLEAR_LOGICAL          2
+#define SK_ADDR_SET_LOGICAL                    4
+
+/* ----- Override return values ----- */
+
+#define SK_ADDR_OVERRIDE_SUCCESS       (SK_ADDR_SUCCESS)
+#define SK_ADDR_DUPLICATE_ADDRESS      1
+#define SK_ADDR_MULTICAST_ADDRESS      2
+
+/* ----- Partitioning of excact match table ----- */
+
+#define SK_ADDR_EXACT_MATCHES          16      /* #Exact match entries. */
+
+#define SK_ADDR_FIRST_MATCH_RLMT       1
+#define SK_ADDR_LAST_MATCH_RLMT                2
+#define SK_ADDR_FIRST_MATCH_DRV                3
+#define SK_ADDR_LAST_MATCH_DRV         (SK_ADDR_EXACT_MATCHES - 1)
+
+/* ----- SkAddrMcAdd/SkAddrMcUpdate return values ----- */
+
+#define SK_MC_FILTERING_EXACT          0       /* Exact filtering. */
+#define SK_MC_FILTERING_INEXACT                1       /* Inexact filtering. */
+
+/* ----- Additional SkAddrMcAdd return values ----- */
+
+#define SK_MC_ILLEGAL_ADDRESS          2       /* Illegal address. */
+#define SK_MC_ILLEGAL_PORT                     3       /* Illegal port (not the active one). */
+#define SK_MC_RLMT_OVERFLOW                    4       /* Too many RLMT mc addresses. */
+
+/* Promiscuous mode bits ----- */
+
+#define SK_PROM_MODE_NONE                      0       /* Normal receive. */
+#define SK_PROM_MODE_LLC                       1       /* Receive all LLC frames. */
+#define SK_PROM_MODE_ALL_MC                    2       /* Receive all multicast frames. */
+/* #define SK_PROM_MODE_NON_LLC                4 */    /* Receive all non-LLC frames. */
+
+/* Macros */
+
+#ifdef OLD_STUFF
+#ifndef SK_ADDR_EQUAL
+/*
+ * "&" instead of "&&" allows better optimization on IA-64.
+ * The replacement is safe here, as all bytes exist.
+ */
+#ifndef SK_ADDR_DWORD_COMPARE
+#define SK_ADDR_EQUAL(A1,A2)   ( \
+       (((SK_U8 *)(A1))[5] == ((SK_U8 *)(A2))[5]) & \
+       (((SK_U8 *)(A1))[4] == ((SK_U8 *)(A2))[4]) & \
+       (((SK_U8 *)(A1))[3] == ((SK_U8 *)(A2))[3]) & \
+       (((SK_U8 *)(A1))[2] == ((SK_U8 *)(A2))[2]) & \
+       (((SK_U8 *)(A1))[1] == ((SK_U8 *)(A2))[1]) & \
+       (((SK_U8 *)(A1))[0] == ((SK_U8 *)(A2))[0]))
+#else  /* SK_ADDR_DWORD_COMPARE */
+#define SK_ADDR_EQUAL(A1,A2)   ( \
+       (*(SK_U32 *)&(((SK_U8 *)(A1))[2]) == *(SK_U32 *)&(((SK_U8 *)(A2))[2])) & \
+       (*(SK_U32 *)&(((SK_U8 *)(A1))[0]) == *(SK_U32 *)&(((SK_U8 *)(A2))[0])))
+#endif /* SK_ADDR_DWORD_COMPARE */
+#endif /* SK_ADDR_EQUAL */
+#endif /* 0 */
+
+#ifndef SK_ADDR_EQUAL
+#ifndef SK_ADDR_DWORD_COMPARE
+#define SK_ADDR_EQUAL(A1,A2)   ( \
+       (((SK_U8 SK_FAR *)(A1))[5] == ((SK_U8 SK_FAR *)(A2))[5]) & \
+       (((SK_U8 SK_FAR *)(A1))[4] == ((SK_U8 SK_FAR *)(A2))[4]) & \
+       (((SK_U8 SK_FAR *)(A1))[3] == ((SK_U8 SK_FAR *)(A2))[3]) & \
+       (((SK_U8 SK_FAR *)(A1))[2] == ((SK_U8 SK_FAR *)(A2))[2]) & \
+       (((SK_U8 SK_FAR *)(A1))[1] == ((SK_U8 SK_FAR *)(A2))[1]) & \
+       (((SK_U8 SK_FAR *)(A1))[0] == ((SK_U8 SK_FAR *)(A2))[0]))
+#else  /* SK_ADDR_DWORD_COMPARE */
+#define SK_ADDR_EQUAL(A1,A2)   ( \
+       (*(SK_U16 SK_FAR *)&(((SK_U8 SK_FAR *)(A1))[4]) == \
+       *(SK_U16 SK_FAR *)&(((SK_U8 SK_FAR *)(A2))[4])) && \
+       (*(SK_U32 SK_FAR *)&(((SK_U8 SK_FAR *)(A1))[0]) == \
+       *(SK_U32 SK_FAR *)&(((SK_U8 SK_FAR *)(A2))[0])))
+#endif /* SK_ADDR_DWORD_COMPARE */
+#endif /* SK_ADDR_EQUAL */
+
+/* typedefs *******************************************************************/
+
+typedef struct s_MacAddr {
+       SK_U8   a[SK_MAC_ADDR_LEN];
+} SK_MAC_ADDR;
+
+
+/* SK_FILTER is used to ensure alignment of the filter. */
+typedef union s_InexactFilter {
+       SK_U8   Bytes[8];
+       SK_U64  Val;    /* Dummy entry for alignment only. */
+} SK_FILTER64;
+
+
+typedef struct s_AddrNet SK_ADDR_NET;
+
+
+typedef struct s_AddrPort {
+
+/* ----- Public part (read-only) ----- */
+
+       SK_MAC_ADDR     CurrentMacAddress;      /* Current physical MAC Address. */
+       SK_MAC_ADDR     PermanentMacAddress;    /* Permanent physical MAC Address. */
+       int             PromMode;               /* Promiscuous Mode. */
+
+/* ----- Private part ----- */
+
+       SK_MAC_ADDR     PreviousMacAddress;     /* Prev. phys. MAC Address. */
+       SK_BOOL         CurrentMacAddressSet;   /* CurrentMacAddress is set. */
+       SK_U8           Align01;
+
+       SK_U32          FirstExactMatchRlmt;
+       SK_U32          NextExactMatchRlmt;
+       SK_U32          FirstExactMatchDrv;
+       SK_U32          NextExactMatchDrv;
+       SK_MAC_ADDR     Exact[SK_ADDR_EXACT_MATCHES];
+       SK_FILTER64     InexactFilter;                  /* For 64-bit hash register. */
+       SK_FILTER64     InexactRlmtFilter;              /* For 64-bit hash register. */
+       SK_FILTER64     InexactDrvFilter;               /* For 64-bit hash register. */
+} SK_ADDR_PORT;
+
+
+struct s_AddrNet {
+/* ----- Public part (read-only) ----- */
+
+       SK_MAC_ADDR             CurrentMacAddress;      /* Logical MAC Address. */
+       SK_MAC_ADDR             PermanentMacAddress;    /* Logical MAC Address. */
+
+/* ----- Private part ----- */
+
+       SK_U32                  ActivePort;             /* View of module ADDR. */
+       SK_BOOL                 CurrentMacAddressSet;   /* CurrentMacAddress is set. */
+       SK_U8                   Align01;
+       SK_U16                  Align02;
+};
+
+
+typedef struct s_Addr {
+
+/* ----- Public part (read-only) ----- */
+
+       SK_ADDR_NET             Net[SK_MAX_NETS];
+       SK_ADDR_PORT    Port[SK_MAX_MACS];
+
+/* ----- Private part ----- */
+} SK_ADDR;
+
+/* function prototypes ********************************************************/
+
+#ifndef SK_KR_PROTO
+
+/* Functions provided by SkAddr */
+
+/* ANSI/C++ compliant function prototypes */
+
+extern int     SkAddrInit(
+       SK_AC   *pAC,
+       SK_IOC  IoC,
+       int     Level);
+
+extern int     SkAddrMcClear(
+       SK_AC   *pAC,
+       SK_IOC  IoC,
+       SK_U32  PortNumber,
+       int     Flags);
+
+extern int     SkAddrMcAdd(
+       SK_AC           *pAC,
+       SK_IOC          IoC,
+       SK_U32          PortNumber,
+       SK_MAC_ADDR     *pMc,
+       int             Flags);
+
+extern int     SkAddrMcUpdate(
+       SK_AC   *pAC,
+       SK_IOC  IoC,
+       SK_U32  PortNumber);
+
+extern int     SkAddrOverride(
+       SK_AC           *pAC,
+       SK_IOC          IoC,
+       SK_U32          PortNumber,
+       SK_MAC_ADDR     SK_FAR *pNewAddr,
+       int             Flags);
+
+extern int     SkAddrPromiscuousChange(
+       SK_AC   *pAC,
+       SK_IOC  IoC,
+       SK_U32  PortNumber,
+       int     NewPromMode);
+
+#ifndef SK_SLIM
+extern int     SkAddrSwap(
+       SK_AC   *pAC,
+       SK_IOC  IoC,
+       SK_U32  FromPortNumber,
+       SK_U32  ToPortNumber);
+#endif
+
+#else  /* defined(SK_KR_PROTO)) */
+
+/* Non-ANSI/C++ compliant function prototypes */
+
+#error KR-style prototypes are not yet provided.
+
+#endif /* defined(SK_KR_PROTO)) */
+
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __INC_SKADDR_H */
diff --git a/drivers/net/sk98lin/h/skcsum.h b/drivers/net/sk98lin/h/skcsum.h
new file mode 100644 (file)
index 0000000..6e256bd
--- /dev/null
@@ -0,0 +1,213 @@
+/******************************************************************************
+ *
+ * Name:       skcsum.h
+ * Project:    GEnesis - SysKonnect SK-NET Gigabit Ethernet (SK-98xx)
+ * Version:    $Revision: 1.10 $
+ * Date:       $Date: 2003/08/20 13:59:57 $
+ * Purpose:    Store/verify Internet checksum in send/receive packets.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *     (C)Copyright 1998-2001 SysKonnect GmbH.
+ *
+ *     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.
+ *
+ *     The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * Description:
+ *
+ * Public header file for the "GEnesis" common module "CSUM".
+ *
+ * "GEnesis" is an abbreviation of "Gigabit Ethernet Network System in Silicon"
+ * and is the code name of this SysKonnect project.
+ *
+ * Compilation Options:
+ *
+ *     SK_USE_CSUM - Define if CSUM is to be used. Otherwise, CSUM will be an
+ *     empty module.
+ *
+ *     SKCS_OVERWRITE_PROTO - Define to overwrite the default protocol id
+ *     definitions. In this case, all SKCS_PROTO_xxx definitions must be made
+ *     external.
+ *
+ *     SKCS_OVERWRITE_STATUS - Define to overwrite the default return status
+ *     definitions. In this case, all SKCS_STATUS_xxx definitions must be made
+ *     external.
+ *
+ * Include File Hierarchy:
+ *
+ *     "h/skcsum.h"
+ *      "h/sktypes.h"
+ *      "h/skqueue.h"
+ *
+ ******************************************************************************/
+
+#ifndef __INC_SKCSUM_H
+#define __INC_SKCSUM_H
+
+#include "h/sktypes.h"
+#include "h/skqueue.h"
+
+/* defines ********************************************************************/
+
+/*
+ * Define the default bit flags for 'SKCS_PACKET_INFO.ProtocolFlags'  if no user
+ * overwrite.
+ */
+#ifndef SKCS_OVERWRITE_PROTO   /* User overwrite? */
+#define SKCS_PROTO_IP  0x1     /* IP (Internet Protocol version 4) */
+#define SKCS_PROTO_TCP 0x2     /* TCP (Transmission Control Protocol) */
+#define SKCS_PROTO_UDP 0x4     /* UDP (User Datagram Protocol) */
+
+/* Indices for protocol statistics. */
+#define SKCS_PROTO_STATS_IP    0
+#define SKCS_PROTO_STATS_UDP   1
+#define SKCS_PROTO_STATS_TCP   2
+#define SKCS_NUM_PROTOCOLS     3       /* Number of supported protocols. */
+#endif /* !SKCS_OVERWRITE_PROTO */
+
+/*
+ * Define the default SKCS_STATUS type and values if no user overwrite.
+ *
+ *     SKCS_STATUS_UNKNOWN_IP_VERSION - Not an IP v4 frame.
+ *     SKCS_STATUS_IP_CSUM_ERROR - IP checksum error.
+ *     SKCS_STATUS_IP_CSUM_ERROR_TCP - IP checksum error in TCP frame.
+ *     SKCS_STATUS_IP_CSUM_ERROR_UDP - IP checksum error in UDP frame
+ *     SKCS_STATUS_IP_FRAGMENT - IP fragment (IP checksum ok).
+ *     SKCS_STATUS_IP_CSUM_OK - IP checksum ok (not a TCP or UDP frame).
+ *     SKCS_STATUS_TCP_CSUM_ERROR - TCP checksum error (IP checksum ok).
+ *     SKCS_STATUS_UDP_CSUM_ERROR - UDP checksum error (IP checksum ok).
+ *     SKCS_STATUS_TCP_CSUM_OK - IP and TCP checksum ok.
+ *     SKCS_STATUS_UDP_CSUM_OK - IP and UDP checksum ok.
+ *     SKCS_STATUS_IP_CSUM_OK_NO_UDP - IP checksum OK and no UDP checksum. 
+ */
+#ifndef SKCS_OVERWRITE_STATUS  /* User overwrite? */
+#define SKCS_STATUS    int     /* Define status type. */
+
+#define SKCS_STATUS_UNKNOWN_IP_VERSION 1
+#define SKCS_STATUS_IP_CSUM_ERROR              2
+#define SKCS_STATUS_IP_FRAGMENT                        3
+#define SKCS_STATUS_IP_CSUM_OK                 4
+#define SKCS_STATUS_TCP_CSUM_ERROR             5
+#define SKCS_STATUS_UDP_CSUM_ERROR             6
+#define SKCS_STATUS_TCP_CSUM_OK                        7
+#define SKCS_STATUS_UDP_CSUM_OK                        8
+/* needed for Microsoft */
+#define SKCS_STATUS_IP_CSUM_ERROR_UDP  9
+#define SKCS_STATUS_IP_CSUM_ERROR_TCP  10
+/* UDP checksum may be omitted */
+#define SKCS_STATUS_IP_CSUM_OK_NO_UDP  11
+#endif /* !SKCS_OVERWRITE_STATUS */
+
+/* Clear protocol statistics event. */
+#define SK_CSUM_EVENT_CLEAR_PROTO_STATS        1
+
+/*
+ * Add two values in one's complement.
+ *
+ * Note: One of the two input values may be "longer" than 16-bit, but then the
+ * resulting sum may be 17 bits long. In this case, add zero to the result using
+ * SKCS_OC_ADD() again.
+ *
+ *     Result = Value1 + Value2
+ */
+#define SKCS_OC_ADD(Result, Value1, Value2) {                          \
+       unsigned long Sum;                                              \
+                                                                       \
+       Sum = (unsigned long) (Value1) + (unsigned long) (Value2);      \
+       /* Add-in any carry. */                                         \
+       (Result) = (Sum & 0xffff) + (Sum >> 16);                        \
+}
+
+/*
+ * Subtract two values in one's complement.
+ *
+ *     Result = Value1 - Value2
+ */
+#define SKCS_OC_SUB(Result, Value1, Value2)    \
+       SKCS_OC_ADD((Result), (Value1), ~(Value2) & 0xffff)
+
+/* typedefs *******************************************************************/
+
+/*
+ * SKCS_PROTO_STATS - The CSUM protocol statistics structure.
+ *
+ * There is one instance of this structure for each protocol supported.
+ */
+typedef struct s_CsProtocolStatistics {
+       SK_U64 RxOkCts;         /* Receive checksum ok. */
+       SK_U64 RxUnableCts;     /* Unable to verify receive checksum. */
+       SK_U64 RxErrCts;        /* Receive checksum error. */
+       SK_U64 TxOkCts;         /* Transmit checksum ok. */
+       SK_U64 TxUnableCts;     /* Unable to calculate checksum in hw. */
+} SKCS_PROTO_STATS;
+
+/*
+ * s_Csum - The CSUM module context structure.
+ */
+typedef struct s_Csum {
+       /* Enabled receive SK_PROTO_XXX bit flags. */
+       unsigned ReceiveFlags[SK_MAX_NETS];
+#ifdef TX_CSUM
+       unsigned TransmitFlags[SK_MAX_NETS];
+#endif /* TX_CSUM */
+
+       /* The protocol statistics structure; one per supported protocol. */
+       SKCS_PROTO_STATS ProtoStats[SK_MAX_NETS][SKCS_NUM_PROTOCOLS];
+} SK_CSUM;
+
+/*
+ * SKCS_PACKET_INFO - The packet information structure.
+ */
+typedef struct s_CsPacketInfo {
+       /* Bit field specifiying the desired/found protocols. */
+       unsigned ProtocolFlags;
+
+       /* Length of complete IP header, including any option fields. */
+       unsigned IpHeaderLength;
+
+       /* IP header checksum. */
+       unsigned IpHeaderChecksum;
+
+       /* TCP/UDP pseudo header checksum. */
+       unsigned PseudoHeaderChecksum;
+} SKCS_PACKET_INFO;
+
+/* function prototypes ********************************************************/
+
+#ifndef SK_CS_CALCULATE_CHECKSUM
+extern unsigned SkCsCalculateChecksum(
+       void            *pData,
+       unsigned        Length);
+#endif /* SK_CS_CALCULATE_CHECKSUM */
+
+extern int SkCsEvent(
+       SK_AC           *pAc,
+       SK_IOC          Ioc,
+       SK_U32          Event,
+       SK_EVPARA       Param);
+
+extern SKCS_STATUS SkCsGetReceiveInfo(
+       SK_AC           *pAc,
+       void            *pIpHeader,
+       unsigned        Checksum1,
+       unsigned        Checksum2,
+       int                     NetNumber);
+
+extern void SkCsSetReceiveFlags(
+       SK_AC           *pAc,
+       unsigned        ReceiveFlags,
+       unsigned        *pChecksum1Offset,
+       unsigned        *pChecksum2Offset,
+       int                     NetNumber);
+
+#endif /* __INC_SKCSUM_H */
diff --git a/drivers/net/sk98lin/h/skdebug.h b/drivers/net/sk98lin/h/skdebug.h
new file mode 100644 (file)
index 0000000..3cba171
--- /dev/null
@@ -0,0 +1,74 @@
+/******************************************************************************
+ *
+ * Name:       skdebug.h
+ * Project:    Gigabit Ethernet Adapters, Common Modules
+ * Version:    $Revision: 1.14 $
+ * Date:       $Date: 2003/05/13 17:26:00 $
+ * Purpose:    SK specific DEBUG support
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *     (C)Copyright 1998-2002 SysKonnect.
+ *     (C)Copyright 2002-2003 Marvell.
+ *
+ *     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.
+ *
+ *     The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+#ifndef __INC_SKDEBUG_H
+#define __INC_SKDEBUG_H
+
+#ifdef DEBUG
+#ifndef SK_DBG_MSG
+#define SK_DBG_MSG(pAC,comp,cat,arg) \
+               if ( ((comp) & SK_DBG_CHKMOD(pAC)) &&   \
+                     ((cat) & SK_DBG_CHKCAT(pAC)) ) {  \
+                       SK_DBG_PRINTF arg ;             \
+               }
+#endif
+#else
+#define SK_DBG_MSG(pAC,comp,lev,arg)
+#endif
+
+/* PLS NOTE:
+ * =========
+ * Due to any restrictions of kernel printf routines do not use other
+ * format identifiers as: %x %d %c %s .
+ * Never use any combined format identifiers such as: %lx %ld in your
+ * printf - argument (arg) because some OS specific kernel printfs may
+ * only support some basic identifiers.
+ */
+
+/* Debug modules */
+
+#define SK_DBGMOD_MERR 0x00000001L     /* general module error indication */
+#define SK_DBGMOD_HWM  0x00000002L     /* Hardware init module */
+#define SK_DBGMOD_RLMT 0x00000004L     /* RLMT module */
+#define SK_DBGMOD_VPD  0x00000008L     /* VPD module */
+#define SK_DBGMOD_I2C  0x00000010L     /* I2C module */
+#define SK_DBGMOD_PNMI 0x00000020L     /* PNMI module */
+#define SK_DBGMOD_CSUM 0x00000040L     /* CSUM module */
+#define SK_DBGMOD_ADDR 0x00000080L     /* ADDR module */
+#define SK_DBGMOD_PECP 0x00000100L     /* PECP module */
+#define SK_DBGMOD_POWM 0x00000200L     /* Power Management module */
+
+/* Debug events */
+
+#define SK_DBGCAT_INIT 0x00000001L     /* module/driver initialization */
+#define SK_DBGCAT_CTRL 0x00000002L     /* controlling devices */
+#define SK_DBGCAT_ERR  0x00000004L     /* error handling paths */
+#define SK_DBGCAT_TX   0x00000008L     /* transmit path */
+#define SK_DBGCAT_RX   0x00000010L     /* receive path */
+#define SK_DBGCAT_IRQ  0x00000020L     /* general IRQ handling */
+#define SK_DBGCAT_QUEUE        0x00000040L     /* any queue management */
+#define SK_DBGCAT_DUMP 0x00000080L     /* large data output e.g. hex dump */
+#define SK_DBGCAT_FATAL        0x00000100L     /* fatal error */
+
+#endif /* __INC_SKDEBUG_H */
diff --git a/drivers/net/sk98lin/h/skdrv1st.h b/drivers/net/sk98lin/h/skdrv1st.h
new file mode 100644 (file)
index 0000000..91b8d4f
--- /dev/null
@@ -0,0 +1,188 @@
+/******************************************************************************
+ *
+ * Name:       skdrv1st.h
+ * Project:    GEnesis, PCI Gigabit Ethernet Adapter
+ * Version:    $Revision: 1.4 $
+ * Date:       $Date: 2003/11/12 14:28:14 $
+ * Purpose:    First header file for driver and all other modules
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *     (C)Copyright 1998-2002 SysKonnect GmbH.
+ *     (C)Copyright 2002-2003 Marvell.
+ *
+ *     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.
+ *
+ *     The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * Description:
+ *
+ * This is the first include file of the driver, which includes all
+ * neccessary system header files and some of the GEnesis header files.
+ * It also defines some basic items.
+ *
+ * Include File Hierarchy:
+ *
+ *     see skge.c
+ *
+ ******************************************************************************/
+
+#ifndef __INC_SKDRV1ST_H
+#define __INC_SKDRV1ST_H
+
+typedef struct s_AC    SK_AC;
+
+/* Set card versions */
+#define SK_FAR
+
+/* override some default functions with optimized linux functions */
+
+#define SK_PNMI_STORE_U16(p,v)         memcpy((char*)(p),(char*)&(v),2)
+#define SK_PNMI_STORE_U32(p,v)         memcpy((char*)(p),(char*)&(v),4)
+#define SK_PNMI_STORE_U64(p,v)         memcpy((char*)(p),(char*)&(v),8)
+#define SK_PNMI_READ_U16(p,v)          memcpy((char*)&(v),(char*)(p),2)
+#define SK_PNMI_READ_U32(p,v)          memcpy((char*)&(v),(char*)(p),4)
+#define SK_PNMI_READ_U64(p,v)          memcpy((char*)&(v),(char*)(p),8)
+
+#define SK_ADDR_EQUAL(a1,a2)           (!memcmp(a1,a2,6))
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/bitops.h>
+#include <asm/byteorder.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+
+#include <linux/init.h>
+#include <asm/uaccess.h>
+#include <net/checksum.h>
+
+#define SK_CS_CALCULATE_CHECKSUM
+#ifndef CONFIG_X86_64
+#define SkCsCalculateChecksum(p,l)     ((~ip_compute_csum(p, l)) & 0xffff)
+#else
+#define SkCsCalculateChecksum(p,l)     ((~ip_fast_csum(p, l)) & 0xffff)
+#endif
+
+#include       "h/sktypes.h"
+#include       "h/skerror.h"
+#include       "h/skdebug.h"
+#include       "h/lm80.h"
+#include       "h/xmac_ii.h"
+
+#ifdef __LITTLE_ENDIAN
+#define SK_LITTLE_ENDIAN
+#else
+#define SK_BIG_ENDIAN
+#endif
+
+#define SK_NET_DEVICE  net_device
+
+
+/* we use gethrtime(), return unit: nanoseconds */
+#define SK_TICKS_PER_SEC       100
+
+#define        SK_MEM_MAPPED_IO
+
+// #define SK_RLMT_SLOW_LOOKAHEAD
+
+#define SK_MAX_MACS            2
+#define SK_MAX_NETS            2
+
+#define SK_IOC                 char __iomem *
+
+typedef struct s_DrvRlmtMbuf SK_MBUF;
+
+#define        SK_CONST64      INT64_C
+#define        SK_CONSTU64     UINT64_C
+
+#define SK_MEMCPY(dest,src,size)       memcpy(dest,src,size)
+#define SK_MEMCMP(s1,s2,size)          memcmp(s1,s2,size)
+#define SK_MEMSET(dest,val,size)       memset(dest,val,size)
+#define SK_STRLEN(pStr)                        strlen((char*)(pStr))
+#define SK_STRNCPY(pDest,pSrc,size)    strncpy((char*)(pDest),(char*)(pSrc),size)
+#define SK_STRCMP(pStr1,pStr2)         strcmp((char*)(pStr1),(char*)(pStr2))
+
+/* macros to access the adapter */
+#define SK_OUT8(b,a,v)         writeb((v), ((b)+(a)))  
+#define SK_OUT16(b,a,v)                writew((v), ((b)+(a)))  
+#define SK_OUT32(b,a,v)                writel((v), ((b)+(a)))  
+#define SK_IN8(b,a,pv)         (*(pv) = readb((b)+(a)))
+#define SK_IN16(b,a,pv)                (*(pv) = readw((b)+(a)))
+#define SK_IN32(b,a,pv)                (*(pv) = readl((b)+(a)))
+
+#define int8_t         char
+#define int16_t                short
+#define int32_t                long
+#define int64_t                long long
+#define uint8_t                u_char
+#define uint16_t       u_short
+#define uint32_t       u_long
+#define uint64_t       unsigned long long
+#define t_scalar_t     int
+#define t_uscalar_t    unsigned int
+#define uintptr_t      unsigned long
+
+#define __CONCAT__(A,B) A##B
+
+#define INT32_C(a)             __CONCAT__(a,L)
+#define INT64_C(a)             __CONCAT__(a,LL)
+#define UINT32_C(a)            __CONCAT__(a,UL)
+#define UINT64_C(a)            __CONCAT__(a,ULL)
+
+#ifdef DEBUG
+#define SK_DBG_PRINTF          printk
+#ifndef SK_DEBUG_CHKMOD
+#define SK_DEBUG_CHKMOD                0
+#endif
+#ifndef SK_DEBUG_CHKCAT
+#define SK_DEBUG_CHKCAT                0
+#endif
+/* those come from the makefile */
+#define SK_DBG_CHKMOD(pAC)     (SK_DEBUG_CHKMOD)
+#define SK_DBG_CHKCAT(pAC)     (SK_DEBUG_CHKCAT)
+
+extern void SkDbgPrintf(const char *format,...);
+
+#define SK_DBGMOD_DRV                  0x00010000
+
+/**** possible driver debug categories ********************************/
+#define SK_DBGCAT_DRV_ENTRY            0x00010000
+#define SK_DBGCAT_DRV_SAP              0x00020000
+#define SK_DBGCAT_DRV_MCA              0x00040000
+#define SK_DBGCAT_DRV_TX_PROGRESS      0x00080000
+#define SK_DBGCAT_DRV_RX_PROGRESS      0x00100000
+#define SK_DBGCAT_DRV_PROGRESS         0x00200000
+#define SK_DBGCAT_DRV_MSG              0x00400000
+#define SK_DBGCAT_DRV_PROM             0x00800000
+#define SK_DBGCAT_DRV_TX_FRAME         0x01000000
+#define SK_DBGCAT_DRV_ERROR            0x02000000
+#define SK_DBGCAT_DRV_INT_SRC          0x04000000
+#define SK_DBGCAT_DRV_EVENT            0x08000000
+
+#endif
+
+#define SK_ERR_LOG             SkErrorLog
+
+extern void SkErrorLog(SK_AC*, int, int, char*);
+
+#endif
+
diff --git a/drivers/net/sk98lin/h/skdrv2nd.h b/drivers/net/sk98lin/h/skdrv2nd.h
new file mode 100644 (file)
index 0000000..3fa6717
--- /dev/null
@@ -0,0 +1,447 @@
+/******************************************************************************
+ *
+ * Name:       skdrv2nd.h
+ * Project:    GEnesis, PCI Gigabit Ethernet Adapter
+ * Version:    $Revision: 1.10 $
+ * Date:       $Date: 2003/12/11 16:04:45 $
+ * Purpose:    Second header file for driver and all other modules
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *     (C)Copyright 1998-2002 SysKonnect GmbH.
+ *     (C)Copyright 2002-2003 Marvell.
+ *
+ *     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.
+ *
+ *     The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * Description:
+ *
+ * This is the second include file of the driver, which includes all other
+ * neccessary files and defines all structures and constants used by the
+ * driver and the common modules.
+ *
+ * Include File Hierarchy:
+ *
+ *     see skge.c
+ *
+ ******************************************************************************/
+
+#ifndef __INC_SKDRV2ND_H
+#define __INC_SKDRV2ND_H
+
+#include "h/skqueue.h"
+#include "h/skgehwt.h"
+#include "h/sktimer.h"
+#include "h/ski2c.h"
+#include "h/skgepnmi.h"
+#include "h/skvpd.h"
+#include "h/skgehw.h"
+#include "h/skgeinit.h"
+#include "h/skaddr.h"
+#include "h/skgesirq.h"
+#include "h/skcsum.h"
+#include "h/skrlmt.h"
+#include "h/skgedrv.h"
+
+
+extern SK_MBUF         *SkDrvAllocRlmtMbuf(SK_AC*, SK_IOC, unsigned);
+extern void            SkDrvFreeRlmtMbuf(SK_AC*, SK_IOC, SK_MBUF*);
+extern SK_U64          SkOsGetTime(SK_AC*);
+extern int             SkPciReadCfgDWord(SK_AC*, int, SK_U32*);
+extern int             SkPciReadCfgWord(SK_AC*, int, SK_U16*);
+extern int             SkPciReadCfgByte(SK_AC*, int, SK_U8*);
+extern int             SkPciWriteCfgWord(SK_AC*, int, SK_U16);
+extern int             SkPciWriteCfgByte(SK_AC*, int, SK_U8);
+extern int             SkDrvEvent(SK_AC*, SK_IOC IoC, SK_U32, SK_EVPARA);
+
+#ifdef SK_DIAG_SUPPORT
+extern int             SkDrvEnterDiagMode(SK_AC *pAc);
+extern int             SkDrvLeaveDiagMode(SK_AC *pAc);
+#endif
+
+struct s_DrvRlmtMbuf {
+       SK_MBUF         *pNext;         /* Pointer to next RLMT Mbuf. */
+       SK_U8           *pData;         /* Data buffer (virtually contig.). */
+       unsigned        Size;           /* Data buffer size. */
+       unsigned        Length;         /* Length of packet (<= Size). */
+       SK_U32          PortIdx;        /* Receiving/transmitting port. */
+#ifdef SK_RLMT_MBUF_PRIVATE
+       SK_RLMT_MBUF    Rlmt;           /* Private part for RLMT. */
+#endif  /* SK_RLMT_MBUF_PRIVATE */
+       struct sk_buff  *pOs;           /* Pointer to message block */
+};
+
+
+/*
+ * Time macros
+ */
+#if SK_TICKS_PER_SEC == 100
+#define SK_PNMI_HUNDREDS_SEC(t)        (t)
+#else
+#define SK_PNMI_HUNDREDS_SEC(t)        ((((unsigned long)t) * 100) / \
+                                                                               (SK_TICKS_PER_SEC))
+#endif
+
+/*
+ * New SkOsGetTime
+ */
+#define SkOsGetTimeCurrent(pAC, pUsec) {\
+       struct timeval t;\
+       do_gettimeofday(&t);\
+       *pUsec = ((((t.tv_sec) * 1000000L)+t.tv_usec)/10000);\
+}
+
+
+/*
+ * ioctl definitions
+ */
+#define                SK_IOCTL_BASE           (SIOCDEVPRIVATE)
+#define                SK_IOCTL_GETMIB         (SK_IOCTL_BASE + 0)
+#define                SK_IOCTL_SETMIB         (SK_IOCTL_BASE + 1)
+#define                SK_IOCTL_PRESETMIB      (SK_IOCTL_BASE + 2)
+#define                SK_IOCTL_GEN            (SK_IOCTL_BASE + 3)
+#define                SK_IOCTL_DIAG           (SK_IOCTL_BASE + 4)
+
+typedef struct s_IOCTL SK_GE_IOCTL;
+
+struct s_IOCTL {
+       char __user *   pData;
+       unsigned int    Len;
+};
+
+
+/*
+ * define sizes of descriptor rings in bytes
+ */
+
+#define                TX_RING_SIZE    (8*1024)
+#define                RX_RING_SIZE    (24*1024)
+
+/*
+ * Buffer size for ethernet packets
+ */
+#define        ETH_BUF_SIZE    1540
+#define        ETH_MAX_MTU     1514
+#define ETH_MIN_MTU    60
+#define ETH_MULTICAST_BIT      0x01
+#define SK_JUMBO_MTU   9000
+
+/*
+ * transmit priority selects the queue: LOW=asynchron, HIGH=synchron
+ */
+#define TX_PRIO_LOW    0
+#define TX_PRIO_HIGH   1
+
+/*
+ * alignment of rx/tx descriptors
+ */
+#define DESCR_ALIGN    64
+
+/*
+ * definitions for pnmi. TODO
+ */
+#define SK_DRIVER_RESET(pAC, IoC)      0
+#define SK_DRIVER_SENDEVENT(pAC, IoC)  0
+#define SK_DRIVER_SELFTEST(pAC, IoC)   0
+/* For get mtu you must add an own function */
+#define SK_DRIVER_GET_MTU(pAc,IoC,i)   0
+#define SK_DRIVER_SET_MTU(pAc,IoC,i,v) 0
+#define SK_DRIVER_PRESET_MTU(pAc,IoC,i,v)      0
+
+/*
+** Interim definition of SK_DRV_TIMER placed in this file until 
+** common modules have been finalized
+*/
+#define SK_DRV_TIMER                   11 
+#define        SK_DRV_MODERATION_TIMER         1
+#define SK_DRV_MODERATION_TIMER_LENGTH  1000000  /* 1 second */
+#define SK_DRV_RX_CLEANUP_TIMER                2
+#define SK_DRV_RX_CLEANUP_TIMER_LENGTH 1000000  /* 100 millisecs */
+
+/*
+** Definitions regarding transmitting frames 
+** any calculating any checksum.
+*/
+#define C_LEN_ETHERMAC_HEADER_DEST_ADDR 6
+#define C_LEN_ETHERMAC_HEADER_SRC_ADDR  6
+#define C_LEN_ETHERMAC_HEADER_LENTYPE   2
+#define C_LEN_ETHERMAC_HEADER           ( (C_LEN_ETHERMAC_HEADER_DEST_ADDR) + \
+                                          (C_LEN_ETHERMAC_HEADER_SRC_ADDR)  + \
+                                          (C_LEN_ETHERMAC_HEADER_LENTYPE) )
+
+#define C_LEN_ETHERMTU_MINSIZE          46
+#define C_LEN_ETHERMTU_MAXSIZE_STD      1500
+#define C_LEN_ETHERMTU_MAXSIZE_JUMBO    9000
+
+#define C_LEN_ETHERNET_MINSIZE          ( (C_LEN_ETHERMAC_HEADER) + \
+                                          (C_LEN_ETHERMTU_MINSIZE) )
+
+#define C_OFFSET_IPHEADER               C_LEN_ETHERMAC_HEADER
+#define C_OFFSET_IPHEADER_IPPROTO       9
+#define C_OFFSET_TCPHEADER_TCPCS        16
+#define C_OFFSET_UDPHEADER_UDPCS        6
+
+#define C_OFFSET_IPPROTO                ( (C_LEN_ETHERMAC_HEADER) + \
+                                          (C_OFFSET_IPHEADER_IPPROTO) )
+
+#define C_PROTO_ID_UDP                  17       /* refer to RFC 790 or Stevens'   */
+#define C_PROTO_ID_TCP                  6        /* TCP/IP illustrated for details */
+
+/* TX and RX descriptors *****************************************************/
+
+typedef struct s_RxD RXD; /* the receive descriptor */
+
+struct s_RxD {
+       volatile SK_U32 RBControl;      /* Receive Buffer Control */
+       SK_U32          VNextRxd;       /* Next receive descriptor,low dword */
+       SK_U32          VDataLow;       /* Receive buffer Addr, low dword */
+       SK_U32          VDataHigh;      /* Receive buffer Addr, high dword */
+       SK_U32          FrameStat;      /* Receive Frame Status word */
+       SK_U32          TimeStamp;      /* Time stamp from XMAC */
+       SK_U32          TcpSums;        /* TCP Sum 2 / TCP Sum 1 */
+       SK_U32          TcpSumStarts;   /* TCP Sum Start 2 / TCP Sum Start 1 */
+       RXD             *pNextRxd;      /* Pointer to next Rxd */
+       struct sk_buff  *pMBuf;         /* Pointer to Linux' socket buffer */
+};
+
+typedef struct s_TxD TXD; /* the transmit descriptor */
+
+struct s_TxD {
+       volatile SK_U32 TBControl;      /* Transmit Buffer Control */
+       SK_U32          VNextTxd;       /* Next transmit descriptor,low dword */
+       SK_U32          VDataLow;       /* Transmit Buffer Addr, low dword */
+       SK_U32          VDataHigh;      /* Transmit Buffer Addr, high dword */
+       SK_U32          FrameStat;      /* Transmit Frame Status Word */
+       SK_U32          TcpSumOfs;      /* Reserved / TCP Sum Offset */
+       SK_U16          TcpSumSt;       /* TCP Sum Start */
+       SK_U16          TcpSumWr;       /* TCP Sum Write */
+       SK_U32          TcpReserved;    /* not used */
+       TXD             *pNextTxd;      /* Pointer to next Txd */
+       struct sk_buff  *pMBuf;         /* Pointer to Linux' socket buffer */
+};
+
+/* Used interrupt bits in the interrupts source register *********************/
+
+#define DRIVER_IRQS    ((IS_IRQ_SW)   | \
+                       (IS_R1_F)      |(IS_R2_F)  | \
+                       (IS_XS1_F)     |(IS_XA1_F) | \
+                       (IS_XS2_F)     |(IS_XA2_F))
+
+#define SPECIAL_IRQS   ((IS_HW_ERR)   |(IS_I2C_READY)  | \
+                       (IS_EXT_REG)   |(IS_TIMINT)     | \
+                       (IS_PA_TO_RX1) |(IS_PA_TO_RX2)  | \
+                       (IS_PA_TO_TX1) |(IS_PA_TO_TX2)  | \
+                       (IS_MAC1)      |(IS_LNK_SYNC_M1)| \
+                       (IS_MAC2)      |(IS_LNK_SYNC_M2)| \
+                       (IS_R1_C)      |(IS_R2_C)       | \
+                       (IS_XS1_C)     |(IS_XA1_C)      | \
+                       (IS_XS2_C)     |(IS_XA2_C))
+
+#define IRQ_MASK       ((IS_IRQ_SW)   | \
+                       (IS_R1_B)      |(IS_R1_F)     |(IS_R2_B) |(IS_R2_F) | \
+                       (IS_XS1_B)     |(IS_XS1_F)    |(IS_XA1_B)|(IS_XA1_F)| \
+                       (IS_XS2_B)     |(IS_XS2_F)    |(IS_XA2_B)|(IS_XA2_F)| \
+                       (IS_HW_ERR)    |(IS_I2C_READY)| \
+                       (IS_EXT_REG)   |(IS_TIMINT)   | \
+                       (IS_PA_TO_RX1) |(IS_PA_TO_RX2)| \
+                       (IS_PA_TO_TX1) |(IS_PA_TO_TX2)| \
+                       (IS_MAC1)      |(IS_MAC2)     | \
+                       (IS_R1_C)      |(IS_R2_C)     | \
+                       (IS_XS1_C)     |(IS_XA1_C)    | \
+                       (IS_XS2_C)     |(IS_XA2_C))
+
+#define IRQ_HWE_MASK   (IS_ERR_MSK) /* enable all HW irqs */
+
+typedef struct s_DevNet DEV_NET;
+
+struct s_DevNet {
+       int             PortNr;
+       int             NetNr;
+       SK_AC   *pAC;
+};  
+
+typedef struct s_TxPort                TX_PORT;
+
+struct s_TxPort {
+       /* the transmit descriptor rings */
+       caddr_t         pTxDescrRing;   /* descriptor area memory */
+       SK_U64          VTxDescrRing;   /* descr. area bus virt. addr. */
+       TXD             *pTxdRingHead;  /* Head of Tx rings */
+       TXD             *pTxdRingTail;  /* Tail of Tx rings */
+       TXD             *pTxdRingPrev;  /* descriptor sent previously */
+       int             TxdRingFree;    /* # of free entrys */
+       spinlock_t      TxDesRingLock;  /* serialize descriptor accesses */
+       SK_IOC          HwAddr;         /* bmu registers address */
+       int             PortIndex;      /* index number of port (0 or 1) */
+};
+
+typedef struct s_RxPort                RX_PORT;
+
+struct s_RxPort {
+       /* the receive descriptor rings */
+       caddr_t         pRxDescrRing;   /* descriptor area memory */
+       SK_U64          VRxDescrRing;   /* descr. area bus virt. addr. */
+       RXD             *pRxdRingHead;  /* Head of Rx rings */
+       RXD             *pRxdRingTail;  /* Tail of Rx rings */
+       RXD             *pRxdRingPrev;  /* descriptor given to BMU previously */
+       int             RxdRingFree;    /* # of free entrys */
+       int             RxCsum;         /* use receive checksum hardware */
+       spinlock_t      RxDesRingLock;  /* serialize descriptor accesses */
+       int             RxFillLimit;    /* limit for buffers in ring */
+       SK_IOC          HwAddr;         /* bmu registers address */
+       int             PortIndex;      /* index number of port (0 or 1) */
+};
+
+/* Definitions needed for interrupt moderation *******************************/
+
+#define IRQ_EOF_AS_TX     ((IS_XA1_F)     | (IS_XA2_F))
+#define IRQ_EOF_SY_TX     ((IS_XS1_F)     | (IS_XS2_F))
+#define IRQ_MASK_TX_ONLY  ((IRQ_EOF_AS_TX)| (IRQ_EOF_SY_TX))
+#define IRQ_MASK_RX_ONLY  ((IS_R1_F)      | (IS_R2_F))
+#define IRQ_MASK_SP_ONLY  (SPECIAL_IRQS)
+#define IRQ_MASK_TX_RX    ((IRQ_MASK_TX_ONLY)| (IRQ_MASK_RX_ONLY))
+#define IRQ_MASK_SP_RX    ((SPECIAL_IRQS)    | (IRQ_MASK_RX_ONLY))
+#define IRQ_MASK_SP_TX    ((SPECIAL_IRQS)    | (IRQ_MASK_TX_ONLY))
+#define IRQ_MASK_RX_TX_SP ((SPECIAL_IRQS)    | (IRQ_MASK_TX_RX))
+
+#define C_INT_MOD_NONE                 1
+#define C_INT_MOD_STATIC               2
+#define C_INT_MOD_DYNAMIC              4
+
+#define C_CLK_FREQ_GENESIS      53215000 /* shorter: 53.125 MHz  */
+#define C_CLK_FREQ_YUKON        78215000 /* shorter: 78.125 MHz  */
+
+#define C_INTS_PER_SEC_DEFAULT      2000 
+#define C_INT_MOD_ENABLE_PERCENTAGE   50 /* if higher 50% enable */
+#define C_INT_MOD_DISABLE_PERCENTAGE  50 /* if lower 50% disable */
+#define C_INT_MOD_IPS_LOWER_RANGE     30
+#define C_INT_MOD_IPS_UPPER_RANGE     40000
+
+
+typedef struct s_DynIrqModInfo  DIM_INFO;
+struct s_DynIrqModInfo {
+       unsigned long   PrevTimeVal;
+       unsigned int    PrevSysLoad;
+       unsigned int    PrevUsedTime;
+       unsigned int    PrevTotalTime;
+       int             PrevUsedDescrRatio;
+       int             NbrProcessedDescr;
+        SK_U64          PrevPort0RxIntrCts;
+        SK_U64          PrevPort1RxIntrCts;
+        SK_U64          PrevPort0TxIntrCts;
+        SK_U64          PrevPort1TxIntrCts;
+       SK_BOOL         ModJustEnabled;     /* Moderation just enabled yes/no */
+
+       int             MaxModIntsPerSec;            /* Moderation Threshold */
+       int             MaxModIntsPerSecUpperLimit;  /* Upper limit for DIM  */
+       int             MaxModIntsPerSecLowerLimit;  /* Lower limit for DIM  */
+
+       long            MaskIrqModeration;   /* ModIrqType (eg. 'TxRx')      */
+       SK_BOOL         DisplayStats;        /* Stats yes/no                 */
+       SK_BOOL         AutoSizing;          /* Resize DIM-timer on/off      */
+       int             IntModTypeSelect;    /* EnableIntMod (eg. 'dynamic') */
+
+       SK_TIMER        ModTimer; /* just some timer */
+};
+
+typedef struct s_PerStrm       PER_STRM;
+
+#define SK_ALLOC_IRQ   0x00000001
+
+#ifdef SK_DIAG_SUPPORT
+#define        DIAG_ACTIVE             1
+#define        DIAG_NOTACTIVE          0
+#endif
+
+/****************************************************************************
+ * Per board structure / Adapter Context structure:
+ *     Allocated within attach(9e) and freed within detach(9e).
+ *     Contains all 'per device' necessary handles, flags, locks etc.:
+ */
+struct s_AC  {
+       SK_GEINIT       GIni;           /* GE init struct */
+       SK_PNMI         Pnmi;           /* PNMI data struct */
+       SK_VPD          vpd;            /* vpd data struct */
+       SK_QUEUE        Event;          /* Event queue */
+       SK_HWT          Hwt;            /* Hardware Timer control struct */
+       SK_TIMCTRL      Tim;            /* Software Timer control struct */
+       SK_I2C          I2c;            /* I2C relevant data structure */
+       SK_ADDR         Addr;           /* for Address module */
+       SK_CSUM         Csum;           /* for checksum module */
+       SK_RLMT         Rlmt;           /* for rlmt module */
+       spinlock_t      SlowPathLock;   /* Normal IRQ lock */
+       struct timer_list BlinkTimer;   /* for LED blinking */
+       int             LedsOn;
+       SK_PNMI_STRUCT_DATA PnmiStruct; /* structure to get all Pnmi-Data */
+       int                     RlmtMode;       /* link check mode to set */
+       int                     RlmtNets;       /* Number of nets */
+       
+       SK_IOC          IoBase;         /* register set of adapter */
+       int             BoardLevel;     /* level of active hw init (0-2) */
+
+       SK_U32          AllocFlag;      /* flag allocation of resources */
+       struct pci_dev  *PciDev;        /* for access to pci config space */
+       struct SK_NET_DEVICE    *dev[2];        /* pointer to device struct */
+
+       int             RxBufSize;      /* length of receive buffers */
+        struct net_device_stats stats; /* linux 'netstat -i' statistics */
+       int             Index;          /* internal board index number */
+
+       /* adapter RAM sizes for queues of active port */
+       int             RxQueueSize;    /* memory used for receive queue */
+       int             TxSQueueSize;   /* memory used for sync. tx queue */
+       int             TxAQueueSize;   /* memory used for async. tx queue */
+
+       int             PromiscCount;   /* promiscuous mode counter  */
+       int             AllMultiCount;  /* allmulticast mode counter */
+       int             MulticCount;    /* number of different MC    */
+                                       /*  addresses for this board */
+                                       /*  (may be more than HW can)*/
+
+       int             HWRevision;     /* Hardware revision */
+       int             ActivePort;     /* the active XMAC port */
+       int             MaxPorts;               /* number of activated ports */
+       int             TxDescrPerRing; /* # of descriptors per tx ring */
+       int             RxDescrPerRing; /* # of descriptors per rx ring */
+
+       caddr_t         pDescrMem;      /* Pointer to the descriptor area */
+       dma_addr_t      pDescrMemDMA;   /* PCI DMA address of area */
+
+       /* the port structures with descriptor rings */
+       TX_PORT         TxPort[SK_MAX_MACS][2];
+       RX_PORT         RxPort[SK_MAX_MACS];
+
+       SK_BOOL         CheckQueue;     /* check event queue soon */
+       SK_TIMER        DrvCleanupTimer;/* to check for pending descriptors */
+       DIM_INFO        DynIrqModInfo;  /* all data related to DIM */
+
+       /* Only for tests */
+       int             PortDown;
+       int             ChipsetType;    /*  Chipset family type 
+                                        *  0 == Genesis family support
+                                        *  1 == Yukon family support
+                                        */
+#ifdef SK_DIAG_SUPPORT
+       SK_U32          DiagModeActive;         /* is diag active?      */
+       SK_BOOL         DiagFlowCtrl;           /* for control purposes */
+       SK_PNMI_STRUCT_DATA PnmiBackup;         /* backup structure for all Pnmi-Data */
+       SK_BOOL         WasIfUp[SK_MAX_MACS];   /* for OpenClose while 
+                                                * DIAG is busy with NIC 
+                                                */
+#endif
+
+};
+
+
+#endif /* __INC_SKDRV2ND_H */
+
diff --git a/drivers/net/sk98lin/h/skerror.h b/drivers/net/sk98lin/h/skerror.h
new file mode 100644 (file)
index 0000000..da062f7
--- /dev/null
@@ -0,0 +1,55 @@
+/******************************************************************************
+ *
+ * Name:       skerror.h
+ * Project:    Gigabit Ethernet Adapters, Common Modules
+ * Version:    $Revision: 1.7 $
+ * Date:       $Date: 2003/05/13 17:25:13 $
+ * Purpose:    SK specific Error log support
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *     (C)Copyright 1998-2002 SysKonnect.
+ *     (C)Copyright 2002-2003 Marvell.
+ *
+ *     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.
+ *
+ *     The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+#ifndef _INC_SKERROR_H_
+#define _INC_SKERROR_H_
+
+/*
+ * Define Error Classes
+ */
+#define        SK_ERRCL_OTHER          (0)             /* Other error */
+#define        SK_ERRCL_CONFIG         (1L<<0) /* Configuration error */
+#define        SK_ERRCL_INIT           (1L<<1) /* Initialization error */
+#define        SK_ERRCL_NORES          (1L<<2) /* Out of Resources error */
+#define        SK_ERRCL_SW                     (1L<<3) /* Internal Software error */
+#define        SK_ERRCL_HW                     (1L<<4) /* Hardware Failure */
+#define        SK_ERRCL_COMM           (1L<<5) /* Communication error */
+
+
+/*
+ * Define Error Code Bases
+ */
+#define        SK_ERRBASE_RLMT          100    /* Base Error number for RLMT */
+#define        SK_ERRBASE_HWINIT        200    /* Base Error number for HWInit */
+#define        SK_ERRBASE_VPD           300    /* Base Error number for VPD */
+#define        SK_ERRBASE_PNMI          400    /* Base Error number for PNMI */
+#define        SK_ERRBASE_CSUM          500    /* Base Error number for Checksum */
+#define        SK_ERRBASE_SIRQ          600    /* Base Error number for Special IRQ */
+#define        SK_ERRBASE_I2C           700    /* Base Error number for I2C module */
+#define        SK_ERRBASE_QUEUE         800    /* Base Error number for Scheduler */
+#define        SK_ERRBASE_ADDR          900    /* Base Error number for Address module */
+#define SK_ERRBASE_PECP                1000    /* Base Error number for PECP */
+#define        SK_ERRBASE_DRV          1100    /* Base Error number for Driver */
+
+#endif /* _INC_SKERROR_H_ */
diff --git a/drivers/net/sk98lin/h/skgedrv.h b/drivers/net/sk98lin/h/skgedrv.h
new file mode 100644 (file)
index 0000000..44fd4c3
--- /dev/null
@@ -0,0 +1,51 @@
+/******************************************************************************
+ *
+ * Name:       skgedrv.h
+ * Project:    Gigabit Ethernet Adapters, Common Modules
+ * Version:    $Revision: 1.10 $
+ * Date:       $Date: 2003/07/04 12:25:01 $
+ * Purpose:    Interface with the driver
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *     (C)Copyright 1998-2002 SysKonnect.
+ *     (C)Copyright 2002-2003 Marvell.
+ *
+ *     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.
+ *
+ *     The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+#ifndef __INC_SKGEDRV_H_
+#define __INC_SKGEDRV_H_
+
+/* defines ********************************************************************/
+
+/*
+ * Define the driver events.
+ * Usually the events are defined by the destination module.
+ * In case of the driver we put the definition of the events here.
+ */
+#define SK_DRV_PORT_RESET               1      /* The port needs to be reset */
+#define SK_DRV_NET_UP                   2      /* The net is operational */
+#define SK_DRV_NET_DOWN                         3      /* The net is down */
+#define SK_DRV_SWITCH_SOFT              4      /* Ports switch with both links connected */
+#define SK_DRV_SWITCH_HARD              5      /* Port switch due to link failure */
+#define SK_DRV_RLMT_SEND                6      /* Send a RLMT packet */
+#define SK_DRV_ADAP_FAIL                7      /* The whole adapter fails */
+#define SK_DRV_PORT_FAIL                8      /* One port fails */
+#define SK_DRV_SWITCH_INTERN    9      /* Port switch by the driver itself */
+#define SK_DRV_POWER_DOWN              10      /* Power down mode */
+#define SK_DRV_TIMER                   11      /* Timer for free use */
+#ifdef SK_NO_RLMT
+#define SK_DRV_LINK_UP                 12      /* Link Up event for driver */
+#define SK_DRV_LINK_DOWN               13      /* Link Down event for driver */
+#endif
+#define SK_DRV_DOWNSHIFT_DET   14      /* Downshift 4-Pair / 2-Pair (YUKON only) */
+#endif /* __INC_SKGEDRV_H_ */
diff --git a/drivers/net/sk98lin/h/skgehw.h b/drivers/net/sk98lin/h/skgehw.h
new file mode 100644 (file)
index 0000000..f6282b7
--- /dev/null
@@ -0,0 +1,2126 @@
+/******************************************************************************
+ *
+ * Name:       skgehw.h
+ * Project:    Gigabit Ethernet Adapters, Common Modules
+ * Version:    $Revision: 1.56 $
+ * Date:       $Date: 2003/09/23 09:01:00 $
+ * Purpose:    Defines and Macros for the Gigabit Ethernet Adapter Product Family
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *     (C)Copyright 1998-2002 SysKonnect.
+ *     (C)Copyright 2002-2003 Marvell.
+ *
+ *     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.
+ *
+ *     The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+#ifndef __INC_SKGEHW_H
+#define __INC_SKGEHW_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/* defines ********************************************************************/
+
+#define BIT_31         (1UL << 31)
+#define BIT_30         (1L << 30)
+#define BIT_29         (1L << 29)
+#define BIT_28         (1L << 28)
+#define BIT_27         (1L << 27)
+#define BIT_26         (1L << 26)
+#define BIT_25         (1L << 25)
+#define BIT_24         (1L << 24)
+#define BIT_23         (1L << 23)
+#define BIT_22         (1L << 22)
+#define BIT_21         (1L << 21)
+#define BIT_20         (1L << 20)
+#define BIT_19         (1L << 19)
+#define BIT_18         (1L << 18)
+#define BIT_17         (1L << 17)
+#define BIT_16         (1L << 16)
+#define BIT_15         (1L << 15)
+#define BIT_14         (1L << 14)
+#define BIT_13         (1L << 13)
+#define BIT_12         (1L << 12)
+#define BIT_11         (1L << 11)
+#define BIT_10         (1L << 10)
+#define BIT_9          (1L << 9)
+#define BIT_8          (1L << 8)
+#define BIT_7          (1L << 7)
+#define BIT_6          (1L << 6)
+#define BIT_5          (1L << 5)
+#define BIT_4          (1L << 4)
+#define BIT_3          (1L << 3)
+#define BIT_2          (1L << 2)
+#define BIT_1          (1L << 1)
+#define BIT_0          1L
+
+#define BIT_15S                (1U << 15)
+#define BIT_14S                (1 << 14)
+#define BIT_13S                (1 << 13)
+#define BIT_12S                (1 << 12)
+#define BIT_11S                (1 << 11)
+#define BIT_10S                (1 << 10)
+#define BIT_9S         (1 << 9)
+#define BIT_8S         (1 << 8)
+#define BIT_7S                 (1 << 7)
+#define BIT_6S         (1 << 6)
+#define BIT_5S         (1 << 5)
+#define BIT_4S         (1 << 4)
+#define BIT_3S         (1 << 3)
+#define BIT_2S         (1 << 2)
+#define BIT_1S         (1 << 1)
+#define BIT_0S         1
+
+#define SHIFT31(x)     ((x) << 31)
+#define SHIFT30(x)     ((x) << 30)
+#define SHIFT29(x)     ((x) << 29)
+#define SHIFT28(x)     ((x) << 28)
+#define SHIFT27(x)     ((x) << 27)
+#define SHIFT26(x)     ((x) << 26)
+#define SHIFT25(x)     ((x) << 25)
+#define SHIFT24(x)     ((x) << 24)
+#define SHIFT23(x)     ((x) << 23)
+#define SHIFT22(x)     ((x) << 22)
+#define SHIFT21(x)     ((x) << 21)
+#define SHIFT20(x)     ((x) << 20)
+#define SHIFT19(x)     ((x) << 19)
+#define SHIFT18(x)     ((x) << 18)
+#define SHIFT17(x)     ((x) << 17)
+#define SHIFT16(x)     ((x) << 16)
+#define SHIFT15(x)     ((x) << 15)
+#define SHIFT14(x)     ((x) << 14)
+#define SHIFT13(x)     ((x) << 13)
+#define SHIFT12(x)     ((x) << 12)
+#define SHIFT11(x)     ((x) << 11)
+#define SHIFT10(x)     ((x) << 10)
+#define SHIFT9(x)      ((x) << 9)
+#define SHIFT8(x)      ((x) << 8)
+#define SHIFT7(x)      ((x) << 7)
+#define SHIFT6(x)      ((x) << 6)
+#define SHIFT5(x)      ((x) << 5)
+#define SHIFT4(x)      ((x) << 4)
+#define SHIFT3(x)      ((x) << 3)
+#define SHIFT2(x)      ((x) << 2)
+#define SHIFT1(x)      ((x) << 1)
+#define SHIFT0(x)      ((x) << 0)
+
+/*
+ * Configuration Space header
+ * Since this module is used for different OS', those may be
+ * duplicate on some of them (e.g. Linux). But to keep the
+ * common source, we have to live with this...
+ */
+#define PCI_VENDOR_ID  0x00    /* 16 bit       Vendor ID */
+#define PCI_DEVICE_ID  0x02    /* 16 bit       Device ID */
+#define PCI_COMMAND            0x04    /* 16 bit       Command */
+#define PCI_STATUS             0x06    /* 16 bit       Status */
+#define PCI_REV_ID             0x08    /*  8 bit       Revision ID */
+#define PCI_CLASS_CODE 0x09    /* 24 bit       Class Code */
+#define PCI_CACHE_LSZ  0x0c    /*  8 bit       Cache Line Size */
+#define PCI_LAT_TIM            0x0d    /*  8 bit       Latency Timer */
+#define PCI_HEADER_T   0x0e    /*  8 bit       Header Type */
+#define PCI_BIST               0x0f    /*  8 bit       Built-in selftest */
+#define PCI_BASE_1ST   0x10    /* 32 bit       1st Base address */
+#define PCI_BASE_2ND   0x14    /* 32 bit       2nd Base address */
+       /* Byte 0x18..0x2b:     reserved */
+#define PCI_SUB_VID            0x2c    /* 16 bit       Subsystem Vendor ID */
+#define PCI_SUB_ID             0x2e    /* 16 bit       Subsystem ID */
+#define PCI_BASE_ROM   0x30    /* 32 bit       Expansion ROM Base Address */
+#define PCI_CAP_PTR            0x34    /*  8 bit       Capabilities Ptr */
+       /* Byte 0x35..0x3b:     reserved */
+#define PCI_IRQ_LINE   0x3c    /*  8 bit       Interrupt Line */
+#define PCI_IRQ_PIN            0x3d    /*  8 bit       Interrupt Pin */
+#define PCI_MIN_GNT            0x3e    /*  8 bit       Min_Gnt */
+#define PCI_MAX_LAT            0x3f    /*  8 bit       Max_Lat */
+       /* Device Dependent Region */
+#define PCI_OUR_REG_1  0x40    /* 32 bit       Our Register 1 */
+#define PCI_OUR_REG_2  0x44    /* 32 bit       Our Register 2 */
+       /* Power Management Region */
+#define PCI_PM_CAP_ID  0x48    /*  8 bit       Power Management Cap. ID */
+#define PCI_PM_NITEM   0x49    /*  8 bit       Next Item Ptr */
+#define PCI_PM_CAP_REG 0x4a    /* 16 bit       Power Management Capabilities */
+#define PCI_PM_CTL_STS 0x4c    /* 16 bit       Power Manag. Control/Status */
+       /* Byte 0x4e:   reserved */
+#define PCI_PM_DAT_REG 0x4f    /*  8 bit       Power Manag. Data Register */
+       /* VPD Region */
+#define PCI_VPD_CAP_ID 0x50    /*  8 bit       VPD Cap. ID */
+#define PCI_VPD_NITEM  0x51    /*  8 bit       Next Item Ptr */
+#define PCI_VPD_ADR_REG        0x52    /* 16 bit       VPD Address Register */
+#define PCI_VPD_DAT_REG        0x54    /* 32 bit       VPD Data Register */
+       /* Byte 0x58..0x59:     reserved */
+#define PCI_SER_LD_CTRL        0x5a    /* 16 bit       SEEPROM Loader Ctrl (YUKON only) */
+       /* Byte 0x5c..0xff:     reserved */
+
+/*
+ * I2C Address (PCI Config)
+ *
+ * Note: The temperature and voltage sensors are relocated on a different
+ *      I2C bus.
+ */
+#define I2C_ADDR_VPD   0xa0    /* I2C address for the VPD EEPROM */
+
+/*
+ * Define Bits and Values of the registers
+ */
+/*     PCI_COMMAND     16 bit  Command */
+                                                               /* Bit 15..11:  reserved */
+#define PCI_INT_DIS            BIT_10S         /* Interrupt INTx# disable (PCI 2.3) */
+#define PCI_FBTEN              BIT_9S          /* Fast Back-To-Back enable */
+#define PCI_SERREN             BIT_8S          /* SERR enable */
+#define PCI_ADSTEP             BIT_7S          /* Address Stepping */
+#define PCI_PERREN             BIT_6S          /* Parity Report Response enable */
+#define PCI_VGA_SNOOP  BIT_5S          /* VGA palette snoop */
+#define PCI_MWIEN              BIT_4S          /* Memory write an inv cycl ena */
+#define PCI_SCYCEN             BIT_3S          /* Special Cycle enable */
+#define PCI_BMEN               BIT_2S          /* Bus Master enable */
+#define PCI_MEMEN              BIT_1S          /* Memory Space Access enable */
+#define PCI_IOEN               BIT_0S          /* I/O Space Access enable */
+
+#define PCI_COMMAND_VAL        (PCI_FBTEN | PCI_SERREN | PCI_PERREN | PCI_MWIEN |\
+                                                PCI_BMEN | PCI_MEMEN | PCI_IOEN)
+
+/*     PCI_STATUS      16 bit  Status */
+#define PCI_PERR               BIT_15S         /* Parity Error */
+#define PCI_SERR               BIT_14S         /* Signaled SERR */
+#define PCI_RMABORT            BIT_13S         /* Received Master Abort */
+#define PCI_RTABORT            BIT_12S         /* Received Target Abort */
+                                                               /* Bit 11:      reserved */
+#define PCI_DEVSEL             (3<<9)          /* Bit 10.. 9:  DEVSEL Timing */
+#define PCI_DEV_FAST   (0<<9)          /*              fast */
+#define PCI_DEV_MEDIUM (1<<9)          /*              medium */
+#define PCI_DEV_SLOW   (2<<9)          /*              slow */
+#define PCI_DATAPERR   BIT_8S          /* DATA Parity error detected */
+#define PCI_FB2BCAP            BIT_7S          /* Fast Back-to-Back Capability */
+#define PCI_UDF                        BIT_6S          /* User Defined Features */
+#define PCI_66MHZCAP   BIT_5S          /* 66 MHz PCI bus clock capable */
+#define PCI_NEWCAP             BIT_4S          /* New cap. list implemented */
+#define PCI_INT_STAT   BIT_3S          /* Interrupt INTx# Status (PCI 2.3) */
+                                                               /* Bit  2.. 0:  reserved */
+
+#define PCI_ERRBITS    (PCI_PERR | PCI_SERR | PCI_RMABORT | PCI_RTABORT |\
+                       PCI_DATAPERR)
+
+/*     PCI_CLASS_CODE  24 bit  Class Code */
+/*     Byte 2:         Base Class              (02) */
+/*     Byte 1:         SubClass                (00) */
+/*     Byte 0:         Programming Interface   (00) */
+
+/*     PCI_CACHE_LSZ   8 bit   Cache Line Size */
+/*     Possible values: 0,2,4,8,16,32,64,128   */
+
+/*     PCI_HEADER_T    8 bit   Header Type */
+#define PCI_HD_MF_DEV  BIT_7S  /* 0= single, 1= multi-func dev */
+#define PCI_HD_TYPE            0x7f    /* Bit 6..0:    Header Layout 0= normal */
+
+/*     PCI_BIST        8 bit   Built-in selftest */
+/*     Built-in Self test not supported (optional) */
+
+/*     PCI_BASE_1ST    32 bit  1st Base address */
+#define PCI_MEMSIZE            0x4000L         /* use 16 kB Memory Base */
+#define PCI_MEMBASE_MSK 0xffffc000L    /* Bit 31..14:  Memory Base Address */
+#define PCI_MEMSIZE_MSK 0x00003ff0L    /* Bit 13.. 4:  Memory Size Req. */
+#define PCI_PREFEN             BIT_3           /* Prefetchable */
+#define PCI_MEM_TYP            (3L<<2)         /* Bit  2.. 1:  Memory Type */
+#define PCI_MEM32BIT   (0L<<1)         /* Base addr anywhere in 32 Bit range */
+#define PCI_MEM1M              (1L<<1)         /* Base addr below 1 MegaByte */
+#define PCI_MEM64BIT   (2L<<1)         /* Base addr anywhere in 64 Bit range */
+#define PCI_MEMSPACE   BIT_0           /* Memory Space Indicator */
+
+/*     PCI_BASE_2ND    32 bit  2nd Base address */
+#define PCI_IOBASE             0xffffff00L     /* Bit 31.. 8:  I/O Base address */
+#define PCI_IOSIZE             0x000000fcL     /* Bit  7.. 2:  I/O Size Requirements */
+                                                                       /* Bit  1:      reserved */
+#define PCI_IOSPACE            BIT_0           /* I/O Space Indicator */
+
+/*     PCI_BASE_ROM    32 bit  Expansion ROM Base Address */
+#define PCI_ROMBASE_MSK        0xfffe0000L     /* Bit 31..17:  ROM Base address */
+#define PCI_ROMBASE_SIZ        (0x1cL<<14)     /* Bit 16..14:  Treat as Base or Size */
+#define PCI_ROMSIZE            (0x38L<<11)     /* Bit 13..11:  ROM Size Requirements */
+                                                                       /* Bit 10.. 1:  reserved */
+#define PCI_ROMEN              BIT_0           /* Address Decode enable */
+
+/* Device Dependent Region */
+/*     PCI_OUR_REG_1           32 bit  Our Register 1 */
+                                                                       /* Bit 31..29:  reserved */
+#define PCI_PHY_COMA   BIT_28          /* Set PHY to Coma Mode (YUKON only) */
+#define PCI_TEST_CAL   BIT_27          /* Test PCI buffer calib. (YUKON only) */
+#define PCI_EN_CAL             BIT_26          /* Enable PCI buffer calib. (YUKON only) */
+#define PCI_VIO                        BIT_25          /* PCI I/O Voltage, 0 = 3.3V, 1 = 5V */
+#define PCI_DIS_BOOT   BIT_24          /* Disable BOOT via ROM */
+#define PCI_EN_IO              BIT_23          /* Mapping to I/O space */
+#define PCI_EN_FPROM   BIT_22          /* Enable FLASH mapping to memory */
+                                                                       /*              1 = Map Flash to memory */
+                                                                       /*              0 = Disable addr. dec */
+#define PCI_PAGESIZE   (3L<<20)        /* Bit 21..20:  FLASH Page Size */
+#define PCI_PAGE_16            (0L<<20)        /*              16 k pages      */
+#define PCI_PAGE_32K   (1L<<20)        /*              32 k pages      */
+#define PCI_PAGE_64K   (2L<<20)        /*              64 k pages      */
+#define PCI_PAGE_128K  (3L<<20)        /*              128 k pages     */
+                                                                       /* Bit 19:      reserved        */
+#define PCI_PAGEREG            (7L<<16)        /* Bit 18..16:  Page Register   */
+#define PCI_NOTAR              BIT_15          /* No turnaround cycle */
+#define PCI_FORCE_BE   BIT_14          /* Assert all BEs on MR */
+#define PCI_DIS_MRL            BIT_13          /* Disable Mem Read Line */
+#define PCI_DIS_MRM            BIT_12          /* Disable Mem Read Multiple */
+#define PCI_DIS_MWI            BIT_11          /* Disable Mem Write & Invalidate */
+#define PCI_DISC_CLS   BIT_10          /* Disc: cacheLsz bound */
+#define PCI_BURST_DIS  BIT_9           /* Burst Disable */
+#define PCI_DIS_PCI_CLK        BIT_8           /* Disable PCI clock driving */
+#define PCI_SKEW_DAS   (0xfL<<4)       /* Bit  7.. 4:  Skew Ctrl, DAS Ext */
+#define PCI_SKEW_BASE  0xfL            /* Bit  3.. 0:  Skew Ctrl, Base */
+
+
+/*     PCI_OUR_REG_2           32 bit  Our Register 2 */
+#define PCI_VPD_WR_THR (0xffL<<24)     /* Bit 31..24:  VPD Write Threshold */
+#define PCI_DEV_SEL            (0x7fL<<17)     /* Bit 23..17:  EEPROM Device Select */
+#define PCI_VPD_ROM_SZ (7L<<14)        /* Bit 16..14:  VPD ROM Size    */
+                                                                       /* Bit 13..12:  reserved        */
+#define PCI_PATCH_DIR  (0xfL<<8)       /* Bit 11.. 8:  Ext Patches dir 3..0 */
+#define PCI_PATCH_DIR_3        BIT_11
+#define PCI_PATCH_DIR_2        BIT_10
+#define PCI_PATCH_DIR_1        BIT_9
+#define PCI_PATCH_DIR_0        BIT_8
+#define PCI_EXT_PATCHS (0xfL<<4)       /* Bit  7.. 4:  Extended Patches 3..0 */
+#define PCI_EXT_PATCH_3        BIT_7
+#define PCI_EXT_PATCH_2        BIT_6
+#define PCI_EXT_PATCH_1        BIT_5
+#define PCI_EXT_PATCH_0        BIT_4
+#define PCI_EN_DUMMY_RD        BIT_3           /* Enable Dummy Read */
+#define PCI_REV_DESC   BIT_2           /* Reverse Desc. Bytes */
+                                                                       /* Bit  1:      reserved */
+#define PCI_USEDATA64  BIT_0           /* Use 64Bit Data bus ext */
+
+
+/* Power Management Region */
+/*     PCI_PM_CAP_REG          16 bit  Power Management Capabilities */
+#define PCI_PME_SUP_MSK        (0x1f<<11)      /* Bit 15..11:  PM Event Support Mask */
+#define PCI_PME_D3C_SUP        BIT_15S         /* PME from D3cold Support (if Vaux) */
+#define PCI_PME_D3H_SUP        BIT_14S         /* PME from D3hot Support */
+#define PCI_PME_D2_SUP BIT_13S         /* PME from D2 Support */
+#define PCI_PME_D1_SUP BIT_12S         /* PME from D1 Support */
+#define PCI_PME_D0_SUP BIT_11S         /* PME from D0 Support */
+#define PCI_PM_D2_SUP  BIT_10S         /* D2 Support in 33 MHz mode */
+#define PCI_PM_D1_SUP  BIT_9S          /* D1 Support */
+                                                                       /* Bit  8.. 6:  reserved */
+#define PCI_PM_DSI             BIT_5S          /* Device Specific Initialization */
+#define PCI_PM_APS             BIT_4S          /* Auxialiary Power Source */
+#define PCI_PME_CLOCK  BIT_3S          /* PM Event Clock */
+#define PCI_PM_VER_MSK         7               /* Bit  2.. 0:  PM PCI Spec. version */
+
+/*     PCI_PM_CTL_STS          16 bit  Power Management Control/Status */
+#define PCI_PME_STATUS BIT_15S         /* PME Status (YUKON only) */
+#define PCI_PM_DAT_SCL (3<<13)         /* Bit 14..13:  Data Reg. scaling factor */
+#define PCI_PM_DAT_SEL (0xf<<9)        /* Bit 12.. 9:  PM data selector field */
+#define PCI_PME_EN             BIT_8S          /* Enable PME# generation (YUKON only) */
+                                                                       /* Bit  7.. 2:  reserved */
+#define PCI_PM_STATE_MSK       3               /* Bit  1.. 0:  Power Management State */
+
+#define PCI_PM_STATE_D0                0               /* D0:  Operational (default) */
+#define PCI_PM_STATE_D1                1               /* D1:  (YUKON only) */
+#define PCI_PM_STATE_D2                2               /* D2:  (YUKON only) */
+#define PCI_PM_STATE_D3        3               /* D3:  HOT, Power Down and Reset */
+
+/* VPD Region */
+/*     PCI_VPD_ADR_REG         16 bit  VPD Address Register */
+#define PCI_VPD_FLAG   BIT_15S         /* starts VPD rd/wr cycle */
+#define PCI_VPD_ADR_MSK        0x7fffL         /* Bit 14.. 0:  VPD address mask */
+
+/*     Control Register File (Address Map) */
+
+/*
+ *     Bank 0
+ */
+#define B0_RAP                 0x0000  /*  8 bit       Register Address Port */
+       /* 0x0001 - 0x0003:     reserved */
+#define B0_CTST                        0x0004  /* 16 bit       Control/Status register */
+#define B0_LED                 0x0006  /*  8 Bit       LED register */
+#define B0_POWER_CTRL  0x0007  /*  8 Bit       Power Control reg (YUKON only) */
+#define B0_ISRC                        0x0008  /* 32 bit       Interrupt Source Register */
+#define B0_IMSK                        0x000c  /* 32 bit       Interrupt Mask Register */
+#define B0_HWE_ISRC            0x0010  /* 32 bit       HW Error Interrupt Src Reg */
+#define B0_HWE_IMSK            0x0014  /* 32 bit       HW Error Interrupt Mask Reg */
+#define B0_SP_ISRC             0x0018  /* 32 bit       Special Interrupt Source Reg */
+       /* 0x001c:              reserved */
+
+/* B0 XMAC 1 registers (GENESIS only) */
+#define B0_XM1_IMSK            0x0020  /* 16 bit r/w   XMAC 1 Interrupt Mask Register*/
+       /* 0x0022 - 0x0027:     reserved */
+#define B0_XM1_ISRC            0x0028  /* 16 bit ro    XMAC 1 Interrupt Status Reg */
+       /* 0x002a - 0x002f:     reserved */
+#define B0_XM1_PHY_ADDR 0x0030 /* 16 bit r/w   XMAC 1 PHY Address Register */
+       /* 0x0032 - 0x0033:     reserved */
+#define B0_XM1_PHY_DATA 0x0034 /* 16 bit r/w   XMAC 1 PHY Data Register */
+       /* 0x0036 - 0x003f:     reserved */
+
+/* B0 XMAC 2 registers (GENESIS only) */
+#define B0_XM2_IMSK            0x0040  /* 16 bit r/w   XMAC 2 Interrupt Mask Register*/
+       /* 0x0042 - 0x0047:     reserved */
+#define B0_XM2_ISRC            0x0048  /* 16 bit ro    XMAC 2 Interrupt Status Reg */
+       /* 0x004a - 0x004f:     reserved */
+#define B0_XM2_PHY_ADDR 0x0050 /* 16 bit r/w   XMAC 2 PHY Address Register */
+       /* 0x0052 - 0x0053:     reserved */
+#define B0_XM2_PHY_DATA 0x0054 /* 16 bit r/w   XMAC 2 PHY Data Register */
+       /* 0x0056 - 0x005f:     reserved */
+
+/* BMU Control Status Registers */
+#define B0_R1_CSR              0x0060  /* 32 bit       BMU Ctrl/Stat Rx Queue 1 */
+#define B0_R2_CSR              0x0064  /* 32 bit       BMU Ctrl/Stat Rx Queue 2 */
+#define B0_XS1_CSR             0x0068  /* 32 bit       BMU Ctrl/Stat Sync Tx Queue 1 */
+#define B0_XA1_CSR             0x006c  /* 32 bit       BMU Ctrl/Stat Async Tx Queue 1*/
+#define B0_XS2_CSR             0x0070  /* 32 bit       BMU Ctrl/Stat Sync Tx Queue 2 */
+#define B0_XA2_CSR             0x0074  /* 32 bit       BMU Ctrl/Stat Async Tx Queue 2*/
+       /* 0x0078 - 0x007f:     reserved */
+
+/*
+ *     Bank 1
+ *     - completely empty (this is the RAP Block window)
+ *     Note: if RAP = 1 this page is reserved
+ */
+
+/*
+ *     Bank 2
+ */
+/* NA reg = 48 bit Network Address Register, 3x16 or 8x8 bit readable */
+#define B2_MAC_1               0x0100  /* NA reg        MAC Address 1 */
+       /* 0x0106 - 0x0107:     reserved */
+#define B2_MAC_2               0x0108  /* NA reg        MAC Address 2 */
+       /* 0x010e - 0x010f:     reserved */
+#define B2_MAC_3               0x0110  /* NA reg        MAC Address 3 */
+       /* 0x0116 - 0x0117:     reserved */
+#define B2_CONN_TYP            0x0118  /*  8 bit       Connector type */
+#define B2_PMD_TYP             0x0119  /*  8 bit       PMD type */
+#define B2_MAC_CFG             0x011a  /*  8 bit       MAC Configuration / Chip Revision */
+#define B2_CHIP_ID             0x011b  /*  8 bit       Chip Identification Number */
+       /* Eprom registers are currently of no use */
+#define B2_E_0                 0x011c  /*  8 bit       EPROM Byte 0 (ext. SRAM size */
+#define B2_E_1                 0x011d  /*  8 bit       EPROM Byte 1 (PHY type) */
+#define B2_E_2                 0x011e  /*  8 bit       EPROM Byte 2 */
+#define B2_E_3                 0x011f  /*  8 bit       EPROM Byte 3 */
+#define B2_FAR                 0x0120  /* 32 bit       Flash-Prom Addr Reg/Cnt */
+#define B2_FDP                 0x0124  /*  8 bit       Flash-Prom Data Port */
+       /* 0x0125 - 0x0127:     reserved */
+#define B2_LD_CTRL             0x0128  /*  8 bit       EPROM loader control register */
+#define B2_LD_TEST             0x0129  /*  8 bit       EPROM loader test register */
+       /* 0x012a - 0x012f:     reserved */
+#define B2_TI_INI              0x0130  /* 32 bit       Timer Init Value */
+#define B2_TI_VAL              0x0134  /* 32 bit       Timer Value */
+#define B2_TI_CTRL             0x0138  /*  8 bit       Timer Control */
+#define B2_TI_TEST             0x0139  /*  8 Bit       Timer Test */
+       /* 0x013a - 0x013f:     reserved */
+#define B2_IRQM_INI            0x0140  /* 32 bit       IRQ Moderation Timer Init Reg.*/
+#define B2_IRQM_VAL            0x0144  /* 32 bit       IRQ Moderation Timer Value */
+#define B2_IRQM_CTRL   0x0148  /*  8 bit       IRQ Moderation Timer Control */
+#define B2_IRQM_TEST   0x0149  /*  8 bit       IRQ Moderation Timer Test */
+#define B2_IRQM_MSK    0x014c  /* 32 bit       IRQ Moderation Mask */
+#define B2_IRQM_HWE_MSK 0x0150 /* 32 bit       IRQ Moderation HW Error Mask */
+       /* 0x0154 - 0x0157:     reserved */
+#define B2_TST_CTRL1   0x0158  /*  8 bit       Test Control Register 1 */
+#define B2_TST_CTRL2   0x0159  /*  8 bit       Test Control Register 2 */
+       /* 0x015a - 0x015b:     reserved */
+#define B2_GP_IO               0x015c  /* 32 bit       General Purpose I/O Register */
+#define B2_I2C_CTRL            0x0160  /* 32 bit       I2C HW Control Register */
+#define B2_I2C_DATA            0x0164  /* 32 bit       I2C HW Data Register */
+#define B2_I2C_IRQ             0x0168  /* 32 bit       I2C HW IRQ Register */
+#define B2_I2C_SW              0x016c  /* 32 bit       I2C SW Port Register */
+
+/* Blink Source Counter (GENESIS only) */
+#define B2_BSC_INI             0x0170  /* 32 bit       Blink Source Counter Init Val */
+#define B2_BSC_VAL             0x0174  /* 32 bit       Blink Source Counter Value */
+#define B2_BSC_CTRL            0x0178  /*  8 bit       Blink Source Counter Control */
+#define B2_BSC_STAT            0x0179  /*  8 bit       Blink Source Counter Status */
+#define B2_BSC_TST             0x017a  /* 16 bit       Blink Source Counter Test Reg */
+       /* 0x017c - 0x017f:     reserved */
+
+/*
+ *     Bank 3
+ */
+/* RAM Random Registers */
+#define B3_RAM_ADDR            0x0180  /* 32 bit       RAM Address, to read or write */
+#define B3_RAM_DATA_LO 0x0184  /* 32 bit       RAM Data Word (low dWord) */
+#define B3_RAM_DATA_HI 0x0188  /* 32 bit       RAM Data Word (high dWord) */
+       /* 0x018c - 0x018f:     reserved */
+
+/* RAM Interface Registers */
+/*
+ * The HW-Spec. calls this registers Timeout Value 0..11. But this names are
+ * not usable in SW. Please notice these are NOT real timeouts, these are
+ * the number of qWords transferred continuously.
+ */
+#define B3_RI_WTO_R1   0x0190  /*  8 bit       WR Timeout Queue R1             (TO0) */
+#define B3_RI_WTO_XA1  0x0191  /*  8 bit       WR Timeout Queue XA1    (TO1) */
+#define B3_RI_WTO_XS1  0x0192  /*  8 bit       WR Timeout Queue XS1    (TO2) */
+#define B3_RI_RTO_R1   0x0193  /*  8 bit       RD Timeout Queue R1             (TO3) */
+#define B3_RI_RTO_XA1  0x0194  /*  8 bit       RD Timeout Queue XA1    (TO4) */
+#define B3_RI_RTO_XS1  0x0195  /*  8 bit       RD Timeout Queue XS1    (TO5) */
+#define B3_RI_WTO_R2   0x0196  /*  8 bit       WR Timeout Queue R2             (TO6) */
+#define B3_RI_WTO_XA2  0x0197  /*  8 bit       WR Timeout Queue XA2    (TO7) */
+#define B3_RI_WTO_XS2  0x0198  /*  8 bit       WR Timeout Queue XS2    (TO8) */
+#define B3_RI_RTO_R2   0x0199  /*  8 bit       RD Timeout Queue R2             (TO9) */
+#define B3_RI_RTO_XA2  0x019a  /*  8 bit       RD Timeout Queue XA2    (TO10)*/
+#define B3_RI_RTO_XS2  0x019b  /*  8 bit       RD Timeout Queue XS2    (TO11)*/
+#define B3_RI_TO_VAL   0x019c  /*  8 bit       Current Timeout Count Val */
+       /* 0x019d - 0x019f:     reserved */
+#define B3_RI_CTRL             0x01a0  /* 16 bit       RAM Interface Control Register */
+#define B3_RI_TEST             0x01a2  /*  8 bit       RAM Interface Test Register */
+       /* 0x01a3 - 0x01af:     reserved */
+
+/* MAC Arbiter Registers (GENESIS only) */
+/* these are the no. of qWord transferred continuously and NOT real timeouts */
+#define B3_MA_TOINI_RX1        0x01b0  /*  8 bit       Timeout Init Val Rx Path MAC 1 */
+#define B3_MA_TOINI_RX2        0x01b1  /*  8 bit       Timeout Init Val Rx Path MAC 2 */
+#define B3_MA_TOINI_TX1        0x01b2  /*  8 bit       Timeout Init Val Tx Path MAC 1 */
+#define B3_MA_TOINI_TX2        0x01b3  /*  8 bit       Timeout Init Val Tx Path MAC 2 */
+#define B3_MA_TOVAL_RX1        0x01b4  /*  8 bit       Timeout Value Rx Path MAC 1 */
+#define B3_MA_TOVAL_RX2        0x01b5  /*  8 bit       Timeout Value Rx Path MAC 1 */
+#define B3_MA_TOVAL_TX1        0x01b6  /*  8 bit       Timeout Value Tx Path MAC 2 */
+#define B3_MA_TOVAL_TX2        0x01b7  /*  8 bit       Timeout Value Tx Path MAC 2 */
+#define B3_MA_TO_CTRL  0x01b8  /* 16 bit       MAC Arbiter Timeout Ctrl Reg */
+#define B3_MA_TO_TEST  0x01ba  /* 16 bit       MAC Arbiter Timeout Test Reg */
+       /* 0x01bc - 0x01bf:     reserved */
+#define B3_MA_RCINI_RX1        0x01c0  /*  8 bit       Recovery Init Val Rx Path MAC 1 */
+#define B3_MA_RCINI_RX2        0x01c1  /*  8 bit       Recovery Init Val Rx Path MAC 2 */
+#define B3_MA_RCINI_TX1        0x01c2  /*  8 bit       Recovery Init Val Tx Path MAC 1 */
+#define B3_MA_RCINI_TX2        0x01c3  /*  8 bit       Recovery Init Val Tx Path MAC 2 */
+#define B3_MA_RCVAL_RX1        0x01c4  /*  8 bit       Recovery Value Rx Path MAC 1 */
+#define B3_MA_RCVAL_RX2        0x01c5  /*  8 bit       Recovery Value Rx Path MAC 1 */
+#define B3_MA_RCVAL_TX1        0x01c6  /*  8 bit       Recovery Value Tx Path MAC 2 */
+#define B3_MA_RCVAL_TX2        0x01c7  /*  8 bit       Recovery Value Tx Path MAC 2 */
+#define B3_MA_RC_CTRL  0x01c8  /* 16 bit       MAC Arbiter Recovery Ctrl Reg */
+#define B3_MA_RC_TEST  0x01ca  /* 16 bit       MAC Arbiter Recovery Test Reg */
+       /* 0x01cc - 0x01cf:     reserved */
+
+/* Packet Arbiter Registers (GENESIS only) */
+/* these are real timeouts */
+#define B3_PA_TOINI_RX1        0x01d0  /* 16 bit       Timeout Init Val Rx Path MAC 1 */
+       /* 0x01d2 - 0x01d3:     reserved */
+#define B3_PA_TOINI_RX2        0x01d4  /* 16 bit       Timeout Init Val Rx Path MAC 2 */
+       /* 0x01d6 - 0x01d7:     reserved */
+#define B3_PA_TOINI_TX1        0x01d8  /* 16 bit       Timeout Init Val Tx Path MAC 1 */
+       /* 0x01da - 0x01db:     reserved */
+#define B3_PA_TOINI_TX2        0x01dc  /* 16 bit       Timeout Init Val Tx Path MAC 2 */
+       /* 0x01de - 0x01df:     reserved */
+#define B3_PA_TOVAL_RX1        0x01e0  /* 16 bit       Timeout Val Rx Path MAC 1 */
+       /* 0x01e2 - 0x01e3:     reserved */
+#define B3_PA_TOVAL_RX2        0x01e4  /* 16 bit       Timeout Val Rx Path MAC 2 */
+       /* 0x01e6 - 0x01e7:     reserved */
+#define B3_PA_TOVAL_TX1        0x01e8  /* 16 bit       Timeout Val Tx Path MAC 1 */
+       /* 0x01ea - 0x01eb:     reserved */
+#define B3_PA_TOVAL_TX2        0x01ec  /* 16 bit       Timeout Val Tx Path MAC 2 */
+       /* 0x01ee - 0x01ef:     reserved */
+#define B3_PA_CTRL     0x01f0  /* 16 bit       Packet Arbiter Ctrl Register */
+#define B3_PA_TEST     0x01f2  /* 16 bit       Packet Arbiter Test Register */
+       /* 0x01f4 - 0x01ff:     reserved */
+
+/*
+ *     Bank 4 - 5
+ */
+/* Transmit Arbiter Registers MAC 1 and 2, use MR_ADDR() to access */
+#define TXA_ITI_INI            0x0200  /* 32 bit       Tx Arb Interval Timer Init Val*/
+#define TXA_ITI_VAL            0x0204  /* 32 bit       Tx Arb Interval Timer Value */
+#define TXA_LIM_INI            0x0208  /* 32 bit       Tx Arb Limit Counter Init Val */
+#define TXA_LIM_VAL            0x020c  /* 32 bit       Tx Arb Limit Counter Value */
+#define TXA_CTRL               0x0210  /*  8 bit       Tx Arbiter Control Register */
+#define TXA_TEST               0x0211  /*  8 bit       Tx Arbiter Test Register */
+#define TXA_STAT               0x0212  /*  8 bit       Tx Arbiter Status Register */
+       /* 0x0213 - 0x027f:     reserved */
+       /* 0x0280 - 0x0292:     MAC 2 */
+       /* 0x0213 - 0x027f:     reserved */
+
+/*
+ *     Bank 6
+ */
+/* External registers (GENESIS only) */
+#define B6_EXT_REG             0x0300
+
+/*
+ *     Bank 7
+ */
+/* This is a copy of the Configuration register file (lower half) */
+#define B7_CFG_SPC             0x0380
+
+/*
+ *     Bank 8 - 15
+ */
+/* Receive and Transmit Queue Registers, use Q_ADDR() to access */
+#define B8_Q_REGS              0x0400
+
+/* Queue Register Offsets, use Q_ADDR() to access */
+#define Q_D            0x00    /* 8*32 bit     Current Descriptor */
+#define Q_DA_L 0x20    /* 32 bit       Current Descriptor Address Low dWord */
+#define Q_DA_H 0x24    /* 32 bit       Current Descriptor Address High dWord */
+#define Q_AC_L 0x28    /* 32 bit       Current Address Counter Low dWord */
+#define Q_AC_H 0x2c    /* 32 bit       Current Address Counter High dWord */
+#define Q_BC   0x30    /* 32 bit       Current Byte Counter */
+#define Q_CSR  0x34    /* 32 bit       BMU Control/Status Register */
+#define Q_F            0x38    /* 32 bit       Flag Register */
+#define Q_T1   0x3c    /* 32 bit       Test Register 1 */
+#define Q_T1_TR        0x3c    /*  8 bit       Test Register 1 Transfer SM */
+#define Q_T1_WR        0x3d    /*  8 bit       Test Register 1 Write Descriptor SM */
+#define Q_T1_RD        0x3e    /*  8 bit       Test Register 1 Read Descriptor SM */
+#define Q_T1_SV        0x3f    /*  8 bit       Test Register 1 Supervisor SM */
+#define Q_T2   0x40    /* 32 bit       Test Register 2 */
+#define Q_T3   0x44    /* 32 bit       Test Register 3 */
+       /* 0x48 - 0x7f: reserved */
+
+/*
+ *     Bank 16 - 23
+ */
+/* RAM Buffer Registers */
+#define B16_RAM_REGS   0x0800
+
+/* RAM Buffer Register Offsets, use RB_ADDR() to access */
+#define RB_START               0x00    /* 32 bit       RAM Buffer Start Address */
+#define RB_END                 0x04    /* 32 bit       RAM Buffer End Address */
+#define RB_WP                  0x08    /* 32 bit       RAM Buffer Write Pointer */
+#define RB_RP                  0x0c    /* 32 bit       RAM Buffer Read Pointer */
+#define RB_RX_UTPP             0x10    /* 32 bit       Rx Upper Threshold, Pause Pack */
+#define RB_RX_LTPP             0x14    /* 32 bit       Rx Lower Threshold, Pause Pack */
+#define RB_RX_UTHP             0x18    /* 32 bit       Rx Upper Threshold, High Prio */
+#define RB_RX_LTHP             0x1c    /* 32 bit       Rx Lower Threshold, High Prio */
+       /* 0x10 - 0x1f: reserved at Tx RAM Buffer Registers */
+#define RB_PC                  0x20    /* 32 bit       RAM Buffer Packet Counter */
+#define RB_LEV                 0x24    /* 32 bit       RAM Buffer Level Register */
+#define RB_CTRL                        0x28    /*  8 bit       RAM Buffer Control Register */
+#define RB_TST1                        0x29    /*  8 bit       RAM Buffer Test Register 1 */
+#define RB_TST2                        0x2A    /*  8 bit       RAM Buffer Test Register 2 */
+       /* 0x2c - 0x7f: reserved */
+
+/*
+ *     Bank 24
+ */
+/*
+ * Receive MAC FIFO, Receive LED, and Link_Sync regs (GENESIS only)
+ * use MR_ADDR() to access
+ */
+#define RX_MFF_EA              0x0c00  /* 32 bit       Receive MAC FIFO End Address */
+#define RX_MFF_WP              0x0c04  /* 32 bit       Receive MAC FIFO Write Pointer */
+       /* 0x0c08 - 0x0c0b:     reserved */
+#define RX_MFF_RP              0x0c0c  /* 32 bit       Receive MAC FIFO Read Pointer */
+#define RX_MFF_PC              0x0c10  /* 32 bit       Receive MAC FIFO Packet Cnt */
+#define RX_MFF_LEV             0x0c14  /* 32 bit       Receive MAC FIFO Level */
+#define RX_MFF_CTRL1   0x0c18  /* 16 bit       Receive MAC FIFO Control Reg 1*/
+#define RX_MFF_STAT_TO 0x0c1a  /*  8 bit       Receive MAC Status Timeout */
+#define RX_MFF_TIST_TO 0x0c1b  /*  8 bit       Receive MAC Time Stamp Timeout */
+#define RX_MFF_CTRL2   0x0c1c  /*  8 bit       Receive MAC FIFO Control Reg 2*/
+#define RX_MFF_TST1            0x0c1d  /*  8 bit       Receive MAC FIFO Test Reg 1 */
+#define RX_MFF_TST2            0x0c1e  /*  8 bit       Receive MAC FIFO Test Reg 2 */
+       /* 0x0c1f:      reserved */
+#define RX_LED_INI             0x0c20  /* 32 bit       Receive LED Cnt Init Value */
+#define RX_LED_VAL             0x0c24  /* 32 bit       Receive LED Cnt Current Value */
+#define RX_LED_CTRL            0x0c28  /*  8 bit       Receive LED Cnt Control Reg */
+#define RX_LED_TST             0x0c29  /*  8 bit       Receive LED Cnt Test Register */
+       /* 0x0c2a - 0x0c2f:     reserved */
+#define LNK_SYNC_INI   0x0c30  /* 32 bit       Link Sync Cnt Init Value */
+#define LNK_SYNC_VAL   0x0c34  /* 32 bit       Link Sync Cnt Current Value */
+#define LNK_SYNC_CTRL  0x0c38  /*  8 bit       Link Sync Cnt Control Register */
+#define LNK_SYNC_TST   0x0c39  /*  8 bit       Link Sync Cnt Test Register */
+       /* 0x0c3a - 0x0c3b:     reserved */
+#define LNK_LED_REG            0x0c3c  /*  8 bit       Link LED Register */
+       /* 0x0c3d - 0x0c3f:     reserved */
+
+/* Receive GMAC FIFO (YUKON only), use MR_ADDR() to access */
+#define RX_GMF_EA              0x0c40  /* 32 bit       Rx GMAC FIFO End Address */
+#define RX_GMF_AF_THR  0x0c44  /* 32 bit       Rx GMAC FIFO Almost Full Thresh. */
+#define RX_GMF_CTRL_T  0x0c48  /* 32 bit       Rx GMAC FIFO Control/Test */
+#define RX_GMF_FL_MSK  0x0c4c  /* 32 bit       Rx GMAC FIFO Flush Mask */
+#define RX_GMF_FL_THR  0x0c50  /* 32 bit       Rx GMAC FIFO Flush Threshold */
+       /* 0x0c54 - 0x0c5f:     reserved */
+#define RX_GMF_WP              0x0c60  /* 32 bit       Rx GMAC FIFO Write Pointer */
+       /* 0x0c64 - 0x0c67:     reserved */
+#define RX_GMF_WLEV            0x0c68  /* 32 bit       Rx GMAC FIFO Write Level */
+       /* 0x0c6c - 0x0c6f:     reserved */
+#define RX_GMF_RP              0x0c70  /* 32 bit       Rx GMAC FIFO Read Pointer */
+       /* 0x0c74 - 0x0c77:     reserved */
+#define RX_GMF_RLEV            0x0c78  /* 32 bit       Rx GMAC FIFO Read Level */
+       /* 0x0c7c - 0x0c7f:     reserved */
+
+/*
+ *     Bank 25
+ */
+       /* 0x0c80 - 0x0cbf:     MAC 2 */
+       /* 0x0cc0 - 0x0cff:     reserved */
+
+/*
+ *     Bank 26
+ */
+/*
+ * Transmit MAC FIFO and Transmit LED Registers (GENESIS only),
+ * use MR_ADDR() to access
+ */
+#define TX_MFF_EA              0x0d00  /* 32 bit       Transmit MAC FIFO End Address */
+#define TX_MFF_WP              0x0d04  /* 32 bit       Transmit MAC FIFO WR Pointer */
+#define TX_MFF_WSP             0x0d08  /* 32 bit       Transmit MAC FIFO WR Shadow Ptr */
+#define TX_MFF_RP              0x0d0c  /* 32 bit       Transmit MAC FIFO RD Pointer */
+#define TX_MFF_PC              0x0d10  /* 32 bit       Transmit MAC FIFO Packet Cnt */
+#define TX_MFF_LEV             0x0d14  /* 32 bit       Transmit MAC FIFO Level */
+#define TX_MFF_CTRL1   0x0d18  /* 16 bit       Transmit MAC FIFO Ctrl Reg 1 */
+#define TX_MFF_WAF             0x0d1a  /*  8 bit       Transmit MAC Wait after flush */
+       /* 0x0c1b:      reserved */
+#define TX_MFF_CTRL2   0x0d1c  /*  8 bit       Transmit MAC FIFO Ctrl Reg 2 */
+#define TX_MFF_TST1            0x0d1d  /*  8 bit       Transmit MAC FIFO Test Reg 1 */
+#define TX_MFF_TST2            0x0d1e  /*  8 bit       Transmit MAC FIFO Test Reg 2 */
+       /* 0x0d1f:      reserved */
+#define TX_LED_INI             0x0d20  /* 32 bit       Transmit LED Cnt Init Value */
+#define TX_LED_VAL             0x0d24  /* 32 bit       Transmit LED Cnt Current Val */
+#define TX_LED_CTRL            0x0d28  /*  8 bit       Transmit LED Cnt Control Reg */
+#define TX_LED_TST             0x0d29  /*  8 bit       Transmit LED Cnt Test Reg */
+       /* 0x0d2a - 0x0d3f:     reserved */
+
+/* Transmit GMAC FIFO (YUKON only), use MR_ADDR() to access */
+#define TX_GMF_EA              0x0d40  /* 32 bit       Tx GMAC FIFO End Address */
+#define TX_GMF_AE_THR  0x0d44  /* 32 bit       Tx GMAC FIFO Almost Empty Thresh.*/
+#define TX_GMF_CTRL_T  0x0d48  /* 32 bit       Tx GMAC FIFO Control/Test */
+       /* 0x0d4c - 0x0d5f:     reserved */
+#define TX_GMF_WP              0x0d60  /* 32 bit       Tx GMAC FIFO Write Pointer */
+#define TX_GMF_WSP             0x0d64  /* 32 bit       Tx GMAC FIFO Write Shadow Ptr. */
+#define TX_GMF_WLEV            0x0d68  /* 32 bit       Tx GMAC FIFO Write Level */
+       /* 0x0d6c - 0x0d6f:     reserved */
+#define TX_GMF_RP              0x0d70  /* 32 bit       Tx GMAC FIFO Read Pointer */
+#define TX_GMF_RSTP            0x0d74  /* 32 bit       Tx GMAC FIFO Restart Pointer */
+#define TX_GMF_RLEV            0x0d78  /* 32 bit       Tx GMAC FIFO Read Level */
+       /* 0x0d7c - 0x0d7f:     reserved */
+
+/*
+ *     Bank 27
+ */
+       /* 0x0d80 - 0x0dbf:     MAC 2 */
+       /* 0x0daa - 0x0dff:     reserved */
+
+/*
+ *     Bank 28
+ */
+/* Descriptor Poll Timer Registers */
+#define B28_DPT_INI            0x0e00  /* 24 bit       Descriptor Poll Timer Init Val */
+#define B28_DPT_VAL            0x0e04  /* 24 bit       Descriptor Poll Timer Curr Val */
+#define B28_DPT_CTRL   0x0e08  /*  8 bit       Descriptor Poll Timer Ctrl Reg */
+       /* 0x0e09:      reserved */
+#define B28_DPT_TST            0x0e0a  /*  8 bit       Descriptor Poll Timer Test Reg */
+       /* 0x0e0b:      reserved */
+
+/* Time Stamp Timer Registers (YUKON only) */
+       /* 0x0e10:      reserved */
+#define GMAC_TI_ST_VAL 0x0e14  /* 32 bit       Time Stamp Timer Curr Val */
+#define GMAC_TI_ST_CTRL        0x0e18  /*  8 bit       Time Stamp Timer Ctrl Reg */
+       /* 0x0e19:      reserved */
+#define GMAC_TI_ST_TST 0x0e1a  /*  8 bit       Time Stamp Timer Test Reg */
+       /* 0x0e1b - 0x0e7f:     reserved */
+
+/*
+ *     Bank 29
+ */
+       /* 0x0e80 - 0x0efc:     reserved */
+
+/*
+ *     Bank 30
+ */
+/* GMAC and GPHY Control Registers (YUKON only) */
+#define GMAC_CTRL              0x0f00  /* 32 bit       GMAC Control Reg */
+#define GPHY_CTRL              0x0f04  /* 32 bit       GPHY Control Reg */
+#define GMAC_IRQ_SRC   0x0f08  /*  8 bit       GMAC Interrupt Source Reg */
+       /* 0x0f09 - 0x0f0b:     reserved */
+#define GMAC_IRQ_MSK   0x0f0c  /*  8 bit       GMAC Interrupt Mask Reg */
+       /* 0x0f0d - 0x0f0f:     reserved */
+#define GMAC_LINK_CTRL 0x0f10  /* 16 bit       Link Control Reg */
+       /* 0x0f14 - 0x0f1f:     reserved */
+
+/* Wake-up Frame Pattern Match Control Registers (YUKON only) */
+
+#define WOL_REG_OFFS   0x20    /* HW-Bug: Address is + 0x20 against spec. */
+
+#define WOL_CTRL_STAT  0x0f20  /* 16 bit       WOL Control/Status Reg */
+#define WOL_MATCH_CTL  0x0f22  /*  8 bit       WOL Match Control Reg */
+#define WOL_MATCH_RES  0x0f23  /*  8 bit       WOL Match Result Reg */
+#define WOL_MAC_ADDR_LO        0x0f24  /* 32 bit       WOL MAC Address Low */
+#define WOL_MAC_ADDR_HI        0x0f28  /* 16 bit       WOL MAC Address High */
+#define WOL_PATT_RPTR  0x0f2c  /*  8 bit       WOL Pattern Read Ptr */
+
+/* use this macro to access above registers */
+#define WOL_REG(Reg)   ((Reg) + (pAC->GIni.GIWolOffs))
+
+
+/* WOL Pattern Length Registers (YUKON only) */
+
+#define WOL_PATT_LEN_LO        0x0f30          /* 32 bit       WOL Pattern Length 3..0 */
+#define WOL_PATT_LEN_HI        0x0f34          /* 24 bit       WOL Pattern Length 6..4 */
+
+/* WOL Pattern Counter Registers (YUKON only) */
+
+#define WOL_PATT_CNT_0 0x0f38          /* 32 bit       WOL Pattern Counter 3..0 */
+#define WOL_PATT_CNT_4 0x0f3c          /* 24 bit       WOL Pattern Counter 6..4 */
+       /* 0x0f40 - 0x0f7f:     reserved */
+
+/*
+ *     Bank 31
+ */
+/* 0x0f80 - 0x0fff:    reserved */
+
+/*
+ *     Bank 32 - 33
+ */
+#define WOL_PATT_RAM_1 0x1000  /*  WOL Pattern RAM Link 1 */
+
+/*
+ *     Bank 0x22 - 0x3f
+ */
+/* 0x1100 - 0x1fff:    reserved */
+
+/*
+ *     Bank 0x40 - 0x4f
+ */
+#define BASE_XMAC_1            0x2000  /* XMAC 1 registers */
+
+/*
+ *     Bank 0x50 - 0x5f
+ */
+
+#define BASE_GMAC_1            0x2800  /* GMAC 1 registers */
+
+/*
+ *     Bank 0x60 - 0x6f
+ */
+#define BASE_XMAC_2            0x3000  /* XMAC 2 registers */
+
+/*
+ *     Bank 0x70 - 0x7f
+ */
+#define BASE_GMAC_2            0x3800  /* GMAC 2 registers */
+
+/*
+ *     Control Register Bit Definitions:
+ */
+/*     B0_RAP          8 bit   Register Address Port */
+                                                               /* Bit 7:       reserved */
+#define RAP_RAP                        0x3f    /* Bit 6..0:    0 = block 0,..,6f = block 6f */
+
+/*     B0_CTST                 16 bit  Control/Status register */
+                                                               /* Bit 15..14:  reserved */
+#define CS_CLK_RUN_HOT BIT_13S         /* CLK_RUN hot m. (YUKON-Lite only) */
+#define CS_CLK_RUN_RST BIT_12S         /* CLK_RUN reset  (YUKON-Lite only) */
+#define CS_CLK_RUN_ENA BIT_11S         /* CLK_RUN enable (YUKON-Lite only) */
+#define CS_VAUX_AVAIL  BIT_10S         /* VAUX available (YUKON only) */
+#define CS_BUS_CLOCK   BIT_9S          /* Bus Clock 0/1 = 33/66 MHz */
+#define CS_BUS_SLOT_SZ BIT_8S          /* Slot Size 0/1 = 32/64 bit slot */
+#define CS_ST_SW_IRQ   BIT_7S          /* Set IRQ SW Request */
+#define CS_CL_SW_IRQ   BIT_6S          /* Clear IRQ SW Request */
+#define CS_STOP_DONE   BIT_5S          /* Stop Master is finished */
+#define CS_STOP_MAST   BIT_4S          /* Command Bit to stop the master */
+#define CS_MRST_CLR            BIT_3S          /* Clear Master reset   */
+#define CS_MRST_SET            BIT_2S          /* Set Master reset     */
+#define CS_RST_CLR             BIT_1S          /* Clear Software reset */
+#define CS_RST_SET             BIT_0S          /* Set   Software reset */
+
+/*     B0_LED                   8 Bit  LED register */
+                                                               /* Bit  7.. 2:  reserved */
+#define LED_STAT_ON            BIT_1S          /* Status LED on        */
+#define LED_STAT_OFF   BIT_0S          /* Status LED off       */
+
+/*     B0_POWER_CTRL    8 Bit  Power Control reg (YUKON only) */
+#define PC_VAUX_ENA            BIT_7           /* Switch VAUX Enable  */
+#define PC_VAUX_DIS            BIT_6       /* Switch VAUX Disable */
+#define PC_VCC_ENA             BIT_5       /* Switch VCC Enable  */
+#define PC_VCC_DIS             BIT_4       /* Switch VCC Disable */
+#define PC_VAUX_ON             BIT_3       /* Switch VAUX On  */
+#define PC_VAUX_OFF            BIT_2       /* Switch VAUX Off */
+#define PC_VCC_ON              BIT_1       /* Switch VCC On  */
+#define PC_VCC_OFF             BIT_0       /* Switch VCC Off */
+
+/*     B0_ISRC                 32 bit  Interrupt Source Register */
+/*     B0_IMSK                 32 bit  Interrupt Mask Register */
+/*     B0_SP_ISRC              32 bit  Special Interrupt Source Reg */
+/*     B2_IRQM_MSK     32 bit  IRQ Moderation Mask */
+#define IS_ALL_MSK             0xbfffffffUL    /* All Interrupt bits */
+#define IS_HW_ERR              BIT_31          /* Interrupt HW Error */
+                                                               /* Bit 30:      reserved */
+#define IS_PA_TO_RX1   BIT_29          /* Packet Arb Timeout Rx1 */
+#define IS_PA_TO_RX2   BIT_28          /* Packet Arb Timeout Rx2 */
+#define IS_PA_TO_TX1   BIT_27          /* Packet Arb Timeout Tx1 */
+#define IS_PA_TO_TX2   BIT_26          /* Packet Arb Timeout Tx2 */
+#define IS_I2C_READY   BIT_25          /* IRQ on end of I2C Tx */
+#define IS_IRQ_SW              BIT_24          /* SW forced IRQ        */
+#define IS_EXT_REG             BIT_23          /* IRQ from LM80 or PHY (GENESIS only) */
+                                                                       /* IRQ from PHY (YUKON only) */
+#define IS_TIMINT              BIT_22          /* IRQ from Timer       */
+#define IS_MAC1                        BIT_21          /* IRQ from MAC 1       */
+#define IS_LNK_SYNC_M1 BIT_20          /* Link Sync Cnt wrap MAC 1 */
+#define IS_MAC2                        BIT_19          /* IRQ from MAC 2       */
+#define IS_LNK_SYNC_M2 BIT_18          /* Link Sync Cnt wrap MAC 2 */
+/* Receive Queue 1 */
+#define IS_R1_B                        BIT_17          /* Q_R1 End of Buffer */
+#define IS_R1_F                        BIT_16          /* Q_R1 End of Frame */
+#define IS_R1_C                        BIT_15          /* Q_R1 Encoding Error */
+/* Receive Queue 2 */
+#define IS_R2_B                        BIT_14          /* Q_R2 End of Buffer */
+#define IS_R2_F                        BIT_13          /* Q_R2 End of Frame */
+#define IS_R2_C                        BIT_12          /* Q_R2 Encoding Error */
+/* Synchronous Transmit Queue 1 */
+#define IS_XS1_B               BIT_11          /* Q_XS1 End of Buffer */
+#define IS_XS1_F               BIT_10          /* Q_XS1 End of Frame */
+#define IS_XS1_C               BIT_9           /* Q_XS1 Encoding Error */
+/* Asynchronous Transmit Queue 1 */
+#define IS_XA1_B               BIT_8           /* Q_XA1 End of Buffer */
+#define IS_XA1_F               BIT_7           /* Q_XA1 End of Frame */
+#define IS_XA1_C               BIT_6           /* Q_XA1 Encoding Error */
+/* Synchronous Transmit Queue 2 */
+#define IS_XS2_B               BIT_5           /* Q_XS2 End of Buffer */
+#define IS_XS2_F               BIT_4           /* Q_XS2 End of Frame */
+#define IS_XS2_C               BIT_3           /* Q_XS2 Encoding Error */
+/* Asynchronous Transmit Queue 2 */
+#define IS_XA2_B               BIT_2           /* Q_XA2 End of Buffer */
+#define IS_XA2_F               BIT_1           /* Q_XA2 End of Frame */
+#define IS_XA2_C               BIT_0           /* Q_XA2 Encoding Error */
+
+
+/*     B0_HWE_ISRC             32 bit  HW Error Interrupt Src Reg */
+/*     B0_HWE_IMSK             32 bit  HW Error Interrupt Mask Reg */
+/*     B2_IRQM_HWE_MSK 32 bit  IRQ Moderation HW Error Mask */
+#define IS_ERR_MSK             0x00000fffL     /*              All Error bits */
+                                                               /* Bit 31..14:  reserved */
+#define IS_IRQ_TIST_OV BIT_13  /* Time Stamp Timer Overflow (YUKON only) */
+#define IS_IRQ_SENSOR  BIT_12  /* IRQ from Sensor (YUKON only) */
+#define IS_IRQ_MST_ERR BIT_11  /* IRQ master error detected */
+#define IS_IRQ_STAT            BIT_10  /* IRQ status exception */
+#define IS_NO_STAT_M1  BIT_9   /* No Rx Status from MAC 1 */
+#define IS_NO_STAT_M2  BIT_8   /* No Rx Status from MAC 2 */
+#define IS_NO_TIST_M1  BIT_7   /* No Time Stamp from MAC 1 */
+#define IS_NO_TIST_M2  BIT_6   /* No Time Stamp from MAC 2 */
+#define IS_RAM_RD_PAR  BIT_5   /* RAM Read  Parity Error */
+#define IS_RAM_WR_PAR  BIT_4   /* RAM Write Parity Error */
+#define IS_M1_PAR_ERR  BIT_3   /* MAC 1 Parity Error */
+#define IS_M2_PAR_ERR  BIT_2   /* MAC 2 Parity Error */
+#define IS_R1_PAR_ERR  BIT_1   /* Queue R1 Parity Error */
+#define IS_R2_PAR_ERR  BIT_0   /* Queue R2 Parity Error */
+
+/*     B2_CONN_TYP              8 bit  Connector type */
+/*     B2_PMD_TYP               8 bit  PMD type */
+/*     Values of connector and PMD type comply to SysKonnect internal std */
+
+/*     B2_MAC_CFG               8 bit  MAC Configuration / Chip Revision */
+#define CFG_CHIP_R_MSK (0xf<<4)        /* Bit 7.. 4: Chip Revision */
+                                                                       /* Bit 3.. 2:   reserved */
+#define CFG_DIS_M2_CLK BIT_1S          /* Disable Clock for 2nd MAC */
+#define CFG_SNG_MAC            BIT_0S          /* MAC Config: 0=2 MACs / 1=1 MAC*/
+
+/*     B2_CHIP_ID               8 bit  Chip Identification Number */
+#define CHIP_ID_GENESIS                0x0a    /* Chip ID for GENESIS */
+#define CHIP_ID_YUKON          0xb0    /* Chip ID for YUKON */
+#define CHIP_ID_YUKON_LITE     0xb1    /* Chip ID for YUKON-Lite (Rev. A1-A3) */
+#define CHIP_ID_YUKON_LP       0xb2    /* Chip ID for YUKON-LP */
+
+#define CHIP_REV_YU_LITE_A1    3               /* Chip Rev. for YUKON-Lite A1,A2 */
+#define CHIP_REV_YU_LITE_A3    7               /* Chip Rev. for YUKON-Lite A3 */
+
+/*     B2_FAR                  32 bit  Flash-Prom Addr Reg/Cnt */
+#define FAR_ADDR               0x1ffffL        /* Bit 16.. 0:  FPROM Address mask */
+
+/*     B2_LD_CTRL               8 bit  EPROM loader control register */
+/*     Bits are currently reserved */
+
+/*     B2_LD_TEST               8 bit  EPROM loader test register */
+                                                               /* Bit 7.. 4:   reserved */
+#define LD_T_ON                        BIT_3S  /* Loader Test mode on */
+#define LD_T_OFF               BIT_2S  /* Loader Test mode off */
+#define LD_T_STEP              BIT_1S  /* Decrement FPROM addr. Counter */
+#define LD_START               BIT_0S  /* Start loading FPROM */
+
+/*
+ *     Timer Section
+ */
+/*     B2_TI_CTRL               8 bit  Timer control */
+/*     B2_IRQM_CTRL     8 bit  IRQ Moderation Timer Control */
+                                                               /* Bit 7.. 3:   reserved */
+#define TIM_START              BIT_2S  /* Start Timer */
+#define TIM_STOP               BIT_1S  /* Stop  Timer */
+#define TIM_CLR_IRQ            BIT_0S  /* Clear Timer IRQ (!IRQM) */
+
+/*     B2_TI_TEST               8 Bit  Timer Test */
+/*     B2_IRQM_TEST     8 bit  IRQ Moderation Timer Test */
+/*     B28_DPT_TST              8 bit  Descriptor Poll Timer Test Reg */
+                                                               /* Bit 7.. 3:   reserved */
+#define TIM_T_ON               BIT_2S  /* Test mode on */
+#define TIM_T_OFF              BIT_1S  /* Test mode off */
+#define TIM_T_STEP             BIT_0S  /* Test step */
+
+/*     B28_DPT_INI     32 bit  Descriptor Poll Timer Init Val */
+/*     B28_DPT_VAL     32 bit  Descriptor Poll Timer Curr Val */
+                                                               /* Bit 31..24:  reserved */
+#define DPT_MSK                0x00ffffffL     /* Bit 23.. 0:  Desc Poll Timer Bits */
+
+/*     B28_DPT_CTRL     8 bit  Descriptor Poll Timer Ctrl Reg */
+                                                               /* Bit  7.. 2:  reserved */
+#define DPT_START              BIT_1S  /* Start Descriptor Poll Timer */
+#define DPT_STOP               BIT_0S  /* Stop  Descriptor Poll Timer */
+
+/*     B2_E_3                   8 bit  lower 4 bits used for HW self test result */
+#define B2_E3_RES_MASK 0x0f
+
+/*     B2_TST_CTRL1     8 bit  Test Control Register 1 */
+#define TST_FRC_DPERR_MR       BIT_7S  /* force DATAPERR on MST RD */
+#define TST_FRC_DPERR_MW       BIT_6S  /* force DATAPERR on MST WR */
+#define TST_FRC_DPERR_TR       BIT_5S  /* force DATAPERR on TRG RD */
+#define TST_FRC_DPERR_TW       BIT_4S  /* force DATAPERR on TRG WR */
+#define TST_FRC_APERR_M                BIT_3S  /* force ADDRPERR on MST */
+#define TST_FRC_APERR_T                BIT_2S  /* force ADDRPERR on TRG */
+#define TST_CFG_WRITE_ON       BIT_1S  /* Enable  Config Reg WR */
+#define TST_CFG_WRITE_OFF      BIT_0S  /* Disable Config Reg WR */
+
+/*     B2_TST_CTRL2     8 bit  Test Control Register 2 */
+                                                                       /* Bit 7.. 4:   reserved */
+                       /* force the following error on the next master read/write      */
+#define TST_FRC_DPERR_MR64     BIT_3S  /* DataPERR RD 64       */
+#define TST_FRC_DPERR_MW64     BIT_2S  /* DataPERR WR 64       */
+#define TST_FRC_APERR_1M64     BIT_1S  /* AddrPERR on 1. phase */
+#define TST_FRC_APERR_2M64     BIT_0S  /* AddrPERR on 2. phase */
+
+/*     B2_GP_IO                32 bit  General Purpose I/O Register */
+                                                       /* Bit 31..26:  reserved */
+#define GP_DIR_9       BIT_25  /* IO_9 direct, 0=In/1=Out */
+#define GP_DIR_8       BIT_24  /* IO_8 direct, 0=In/1=Out */
+#define GP_DIR_7       BIT_23  /* IO_7 direct, 0=In/1=Out */
+#define GP_DIR_6       BIT_22  /* IO_6 direct, 0=In/1=Out */
+#define GP_DIR_5       BIT_21  /* IO_5 direct, 0=In/1=Out */
+#define GP_DIR_4       BIT_20  /* IO_4 direct, 0=In/1=Out */
+#define GP_DIR_3       BIT_19  /* IO_3 direct, 0=In/1=Out */
+#define GP_DIR_2       BIT_18  /* IO_2 direct, 0=In/1=Out */
+#define GP_DIR_1       BIT_17  /* IO_1 direct, 0=In/1=Out */
+#define GP_DIR_0       BIT_16  /* IO_0 direct, 0=In/1=Out */
+                                               /* Bit 15..10:  reserved */
+#define GP_IO_9                BIT_9   /* IO_9 pin */
+#define GP_IO_8                BIT_8   /* IO_8 pin */
+#define GP_IO_7                BIT_7   /* IO_7 pin */
+#define GP_IO_6                BIT_6   /* IO_6 pin */
+#define GP_IO_5                BIT_5   /* IO_5 pin */
+#define GP_IO_4                BIT_4   /* IO_4 pin */
+#define GP_IO_3                BIT_3   /* IO_3 pin */
+#define GP_IO_2                BIT_2   /* IO_2 pin */
+#define GP_IO_1                BIT_1   /* IO_1 pin */
+#define GP_IO_0                BIT_0   /* IO_0 pin */
+
+/*     B2_I2C_CTRL             32 bit  I2C HW Control Register */
+#define I2C_FLAG               BIT_31          /* Start read/write if WR */
+#define I2C_ADDR               (0x7fffL<<16)   /* Bit 30..16:  Addr to be RD/WR */
+#define I2C_DEV_SEL            (0x7fL<<9)              /* Bit 15.. 9:  I2C Device Select */
+                                                               /* Bit  8.. 5:  reserved        */
+#define I2C_BURST_LEN  BIT_4           /* Burst Len, 1/4 bytes */
+#define I2C_DEV_SIZE   (7<<1)          /* Bit  3.. 1:  I2C Device Size */
+#define I2C_025K_DEV   (0<<1)          /*              0: 256 Bytes or smal. */
+#define I2C_05K_DEV            (1<<1)          /*              1: 512  Bytes   */
+#define I2C_1K_DEV             (2<<1)          /*              2: 1024 Bytes   */
+#define I2C_2K_DEV             (3<<1)          /*              3: 2048 Bytes   */
+#define I2C_4K_DEV             (4<<1)          /*              4: 4096 Bytes   */
+#define I2C_8K_DEV             (5<<1)          /*              5: 8192 Bytes   */
+#define I2C_16K_DEV            (6<<1)          /*              6: 16384 Bytes  */
+#define I2C_32K_DEV            (7<<1)          /*              7: 32768 Bytes  */
+#define I2C_STOP               BIT_0           /* Interrupt I2C transfer */
+
+/*     B2_I2C_IRQ              32 bit  I2C HW IRQ Register */
+                                                               /* Bit 31.. 1   reserved */
+#define I2C_CLR_IRQ            BIT_0   /* Clear I2C IRQ */
+
+/*     B2_I2C_SW               32 bit (8 bit access)   I2C HW SW Port Register */
+                                                               /* Bit  7.. 3:  reserved */
+#define I2C_DATA_DIR   BIT_2S          /* direction of I2C_DATA */
+#define I2C_DATA               BIT_1S          /* I2C Data Port        */
+#define I2C_CLK                        BIT_0S          /* I2C Clock Port       */
+
+/*
+ * I2C Address
+ */
+#define I2C_SENS_ADDR  LM80_ADDR       /* I2C Sensor Address, (Volt and Temp)*/
+
+
+/*     B2_BSC_CTRL              8 bit  Blink Source Counter Control */
+                                                       /* Bit  7.. 2:  reserved */
+#define BSC_START      BIT_1S          /* Start Blink Source Counter */
+#define BSC_STOP       BIT_0S          /* Stop  Blink Source Counter */
+
+/*     B2_BSC_STAT              8 bit  Blink Source Counter Status */
+                                                       /* Bit  7.. 1:  reserved */
+#define BSC_SRC                BIT_0S          /* Blink Source, 0=Off / 1=On */
+
+/*     B2_BSC_TST              16 bit  Blink Source Counter Test Reg */
+#define BSC_T_ON       BIT_2S          /* Test mode on */
+#define BSC_T_OFF      BIT_1S          /* Test mode off */
+#define BSC_T_STEP     BIT_0S          /* Test step */
+
+
+/*     B3_RAM_ADDR             32 bit  RAM Address, to read or write */
+                                       /* Bit 31..19:  reserved */
+#define RAM_ADR_RAN    0x0007ffffL     /* Bit 18.. 0:  RAM Address Range */
+
+/* RAM Interface Registers */
+/*     B3_RI_CTRL              16 bit  RAM Iface Control Register */
+                                                               /* Bit 15..10:  reserved */
+#define RI_CLR_RD_PERR BIT_9S  /* Clear IRQ RAM Read Parity Err */
+#define RI_CLR_WR_PERR BIT_8S  /* Clear IRQ RAM Write Parity Err*/
+                                                               /* Bit  7.. 2:  reserved */
+#define RI_RST_CLR             BIT_1S  /* Clear RAM Interface Reset */
+#define RI_RST_SET             BIT_0S  /* Set   RAM Interface Reset */
+
+/*     B3_RI_TEST               8 bit  RAM Iface Test Register */
+                                                               /* Bit 15.. 4:  reserved */
+#define RI_T_EV                        BIT_3S  /* Timeout Event occured */
+#define RI_T_ON                        BIT_2S  /* Timeout Timer Test On */
+#define RI_T_OFF               BIT_1S  /* Timeout Timer Test Off */
+#define RI_T_STEP              BIT_0S  /* Timeout Timer Step */
+
+/* MAC Arbiter Registers */
+/*     B3_MA_TO_CTRL   16 bit  MAC Arbiter Timeout Ctrl Reg */
+                                                               /* Bit 15.. 4:  reserved */
+#define MA_FOE_ON              BIT_3S  /* XMAC Fast Output Enable ON */
+#define MA_FOE_OFF             BIT_2S  /* XMAC Fast Output Enable OFF */
+#define MA_RST_CLR             BIT_1S  /* Clear MAC Arbiter Reset */
+#define MA_RST_SET             BIT_0S  /* Set   MAC Arbiter Reset */
+
+/*     B3_MA_RC_CTRL   16 bit  MAC Arbiter Recovery Ctrl Reg */
+                                                               /* Bit 15.. 8:  reserved */
+#define MA_ENA_REC_TX2 BIT_7S  /* Enable  Recovery Timer TX2 */
+#define MA_DIS_REC_TX2 BIT_6S  /* Disable Recovery Timer TX2 */
+#define MA_ENA_REC_TX1 BIT_5S  /* Enable  Recovery Timer TX1 */
+#define MA_DIS_REC_TX1 BIT_4S  /* Disable Recovery Timer TX1 */
+#define MA_ENA_REC_RX2 BIT_3S  /* Enable  Recovery Timer RX2 */
+#define MA_DIS_REC_RX2 BIT_2S  /* Disable Recovery Timer RX2 */
+#define MA_ENA_REC_RX1 BIT_1S  /* Enable  Recovery Timer RX1 */
+#define MA_DIS_REC_RX1 BIT_0S  /* Disable Recovery Timer RX1 */
+
+/* Packet Arbiter Registers */
+/*     B3_PA_CTRL              16 bit  Packet Arbiter Ctrl Register */
+                                                               /* Bit 15..14:  reserved */
+#define PA_CLR_TO_TX2  BIT_13S /* Clear IRQ Packet Timeout TX2 */
+#define PA_CLR_TO_TX1  BIT_12S /* Clear IRQ Packet Timeout TX1 */
+#define PA_CLR_TO_RX2  BIT_11S /* Clear IRQ Packet Timeout RX2 */
+#define PA_CLR_TO_RX1  BIT_10S /* Clear IRQ Packet Timeout RX1 */
+#define PA_ENA_TO_TX2  BIT_9S  /* Enable  Timeout Timer TX2 */
+#define PA_DIS_TO_TX2  BIT_8S  /* Disable Timeout Timer TX2 */
+#define PA_ENA_TO_TX1  BIT_7S  /* Enable  Timeout Timer TX1 */
+#define PA_DIS_TO_TX1  BIT_6S  /* Disable Timeout Timer TX1 */
+#define PA_ENA_TO_RX2  BIT_5S  /* Enable  Timeout Timer RX2 */
+#define PA_DIS_TO_RX2  BIT_4S  /* Disable Timeout Timer RX2 */
+#define PA_ENA_TO_RX1  BIT_3S  /* Enable  Timeout Timer RX1 */
+#define PA_DIS_TO_RX1  BIT_2S  /* Disable Timeout Timer RX1 */
+#define PA_RST_CLR             BIT_1S  /* Clear MAC Arbiter Reset */
+#define PA_RST_SET             BIT_0S  /* Set   MAC Arbiter Reset */
+
+#define PA_ENA_TO_ALL  (PA_ENA_TO_RX1 | PA_ENA_TO_RX2 |\
+                                               PA_ENA_TO_TX1 | PA_ENA_TO_TX2)
+
+/* Rx/Tx Path related Arbiter Test Registers */
+/*     B3_MA_TO_TEST   16 bit  MAC Arbiter Timeout Test Reg */
+/*     B3_MA_RC_TEST   16 bit  MAC Arbiter Recovery Test Reg */
+/*     B3_PA_TEST              16 bit  Packet Arbiter Test Register */
+/*                     Bit 15, 11, 7, and 3 are reserved in B3_PA_TEST */
+#define TX2_T_EV       BIT_15S         /* TX2 Timeout/Recv Event occured */
+#define TX2_T_ON       BIT_14S         /* TX2 Timeout/Recv Timer Test On */
+#define TX2_T_OFF      BIT_13S         /* TX2 Timeout/Recv Timer Tst Off */
+#define TX2_T_STEP     BIT_12S         /* TX2 Timeout/Recv Timer Step */
+#define TX1_T_EV       BIT_11S         /* TX1 Timeout/Recv Event occured */
+#define TX1_T_ON       BIT_10S         /* TX1 Timeout/Recv Timer Test On */
+#define TX1_T_OFF      BIT_9S          /* TX1 Timeout/Recv Timer Tst Off */
+#define TX1_T_STEP     BIT_8S          /* TX1 Timeout/Recv Timer Step */
+#define RX2_T_EV       BIT_7S          /* RX2 Timeout/Recv Event occured */
+#define RX2_T_ON       BIT_6S          /* RX2 Timeout/Recv Timer Test On */
+#define RX2_T_OFF      BIT_5S          /* RX2 Timeout/Recv Timer Tst Off */
+#define RX2_T_STEP     BIT_4S          /* RX2 Timeout/Recv Timer Step */
+#define RX1_T_EV       BIT_3S          /* RX1 Timeout/Recv Event occured */
+#define RX1_T_ON       BIT_2S          /* RX1 Timeout/Recv Timer Test On */
+#define RX1_T_OFF      BIT_1S          /* RX1 Timeout/Recv Timer Tst Off */
+#define RX1_T_STEP     BIT_0S          /* RX1 Timeout/Recv Timer Step */
+
+
+/* Transmit Arbiter Registers MAC 1 and 2, use MR_ADDR() to access */
+/*     TXA_ITI_INI             32 bit  Tx Arb Interval Timer Init Val */
+/*     TXA_ITI_VAL             32 bit  Tx Arb Interval Timer Value */
+/*     TXA_LIM_INI             32 bit  Tx Arb Limit Counter Init Val */
+/*     TXA_LIM_VAL             32 bit  Tx Arb Limit Counter Value */
+                                                               /* Bit 31..24:  reserved */
+#define TXA_MAX_VAL    0x00ffffffUL/* Bit 23.. 0:      Max TXA Timer/Cnt Val */
+
+/*     TXA_CTRL                 8 bit  Tx Arbiter Control Register */
+#define TXA_ENA_FSYNC  BIT_7S  /* Enable  force of sync Tx queue */
+#define TXA_DIS_FSYNC  BIT_6S  /* Disable force of sync Tx queue */
+#define TXA_ENA_ALLOC  BIT_5S  /* Enable  alloc of free bandwidth */
+#define TXA_DIS_ALLOC  BIT_4S  /* Disable alloc of free bandwidth */
+#define TXA_START_RC   BIT_3S  /* Start sync Rate Control */
+#define TXA_STOP_RC            BIT_2S  /* Stop  sync Rate Control */
+#define TXA_ENA_ARB            BIT_1S  /* Enable  Tx Arbiter */
+#define TXA_DIS_ARB            BIT_0S  /* Disable Tx Arbiter */
+
+/*     TXA_TEST                 8 bit  Tx Arbiter Test Register */
+                                                               /* Bit 7.. 6:   reserved */
+#define TXA_INT_T_ON   BIT_5S  /* Tx Arb Interval Timer Test On */
+#define TXA_INT_T_OFF  BIT_4S  /* Tx Arb Interval Timer Test Off */
+#define TXA_INT_T_STEP BIT_3S  /* Tx Arb Interval Timer Step */
+#define TXA_LIM_T_ON   BIT_2S  /* Tx Arb Limit Timer Test On */
+#define TXA_LIM_T_OFF  BIT_1S  /* Tx Arb Limit Timer Test Off */
+#define TXA_LIM_T_STEP BIT_0S  /* Tx Arb Limit Timer Step */
+
+/*     TXA_STAT                 8 bit  Tx Arbiter Status Register */
+                                                               /* Bit 7.. 1:   reserved */
+#define TXA_PRIO_XS            BIT_0S  /* sync queue has prio to send */
+
+/*     Q_BC                    32 bit  Current Byte Counter */
+                                                               /* Bit 31..16:  reserved */
+#define BC_MAX                 0xffff  /* Bit 15.. 0:  Byte counter */
+
+/* BMU Control Status Registers */
+/*     B0_R1_CSR               32 bit  BMU Ctrl/Stat Rx Queue 1 */
+/*     B0_R2_CSR               32 bit  BMU Ctrl/Stat Rx Queue 2 */
+/*     B0_XA1_CSR              32 bit  BMU Ctrl/Stat Sync Tx Queue 1 */
+/*     B0_XS1_CSR              32 bit  BMU Ctrl/Stat Async Tx Queue 1 */
+/*     B0_XA2_CSR              32 bit  BMU Ctrl/Stat Sync Tx Queue 2 */
+/*     B0_XS2_CSR              32 bit  BMU Ctrl/Stat Async Tx Queue 2 */
+/*     Q_CSR                   32 bit  BMU Control/Status Register */
+                                                               /* Bit 31..25:  reserved */
+#define CSR_SV_IDLE            BIT_24          /* BMU SM Idle */
+                                                               /* Bit 23..22:  reserved */
+#define CSR_DESC_CLR   BIT_21          /* Clear Reset for Descr */
+#define CSR_DESC_SET   BIT_20          /* Set   Reset for Descr */
+#define CSR_FIFO_CLR   BIT_19          /* Clear Reset for FIFO */
+#define CSR_FIFO_SET   BIT_18          /* Set   Reset for FIFO */
+#define CSR_HPI_RUN            BIT_17          /* Release HPI SM */
+#define CSR_HPI_RST            BIT_16          /* Reset   HPI SM to Idle */
+#define CSR_SV_RUN             BIT_15          /* Release Supervisor SM */
+#define CSR_SV_RST             BIT_14          /* Reset   Supervisor SM */
+#define CSR_DREAD_RUN  BIT_13          /* Release Descr Read SM */
+#define CSR_DREAD_RST  BIT_12          /* Reset   Descr Read SM */
+#define CSR_DWRITE_RUN BIT_11          /* Release Descr Write SM */
+#define CSR_DWRITE_RST BIT_10          /* Reset   Descr Write SM */
+#define CSR_TRANS_RUN  BIT_9           /* Release Transfer SM */
+#define CSR_TRANS_RST  BIT_8           /* Reset   Transfer SM */
+#define CSR_ENA_POL            BIT_7           /* Enable  Descr Polling */
+#define CSR_DIS_POL            BIT_6           /* Disable Descr Polling */
+#define CSR_STOP               BIT_5           /* Stop  Rx/Tx Queue */
+#define CSR_START              BIT_4           /* Start Rx/Tx Queue */
+#define CSR_IRQ_CL_P   BIT_3           /* (Rx) Clear Parity IRQ */
+#define CSR_IRQ_CL_B   BIT_2           /* Clear EOB IRQ */
+#define CSR_IRQ_CL_F   BIT_1           /* Clear EOF IRQ */
+#define CSR_IRQ_CL_C   BIT_0           /* Clear ERR IRQ */
+
+#define CSR_SET_RESET  (CSR_DESC_SET | CSR_FIFO_SET | CSR_HPI_RST |\
+                                               CSR_SV_RST | CSR_DREAD_RST | CSR_DWRITE_RST |\
+                                               CSR_TRANS_RST)
+#define CSR_CLR_RESET  (CSR_DESC_CLR | CSR_FIFO_CLR | CSR_HPI_RUN |\
+                                               CSR_SV_RUN | CSR_DREAD_RUN | CSR_DWRITE_RUN |\
+                                               CSR_TRANS_RUN)
+
+/*     Q_F                             32 bit  Flag Register */
+                                                                       /* Bit 31..28:  reserved */
+#define F_ALM_FULL             BIT_27          /* Rx FIFO: almost full */
+#define F_EMPTY                        BIT_27          /* Tx FIFO: empty flag */
+#define F_FIFO_EOF             BIT_26          /* Tag (EOF Flag) bit in FIFO */
+#define F_WM_REACHED   BIT_25          /* Watermark reached */
+                                                                       /* reserved */
+#define F_FIFO_LEVEL   (0x1fL<<16)     /* Bit 23..16:  # of Qwords in FIFO */
+                                                                       /* Bit 15..11:  reserved */
+#define F_WATER_MARK   0x0007ffL       /* Bit 10.. 0:  Watermark */
+
+/*     Q_T1                    32 bit  Test Register 1 */
+/*             Holds four State Machine control Bytes */
+#define SM_CTRL_SV_MSK (0xffL<<24)     /* Bit 31..24:  Control Supervisor SM */
+#define SM_CTRL_RD_MSK (0xffL<<16)     /* Bit 23..16:  Control Read Desc SM */
+#define SM_CTRL_WR_MSK (0xffL<<8)      /* Bit 15.. 8:  Control Write Desc SM */
+#define SM_CTRL_TR_MSK 0xffL           /* Bit  7.. 0:  Control Transfer SM */
+
+/*     Q_T1_TR                  8 bit  Test Register 1 Transfer SM */
+/*     Q_T1_WR                  8 bit  Test Register 1 Write Descriptor SM */
+/*     Q_T1_RD                  8 bit  Test Register 1 Read Descriptor SM */
+/*     Q_T1_SV                  8 bit  Test Register 1 Supervisor SM */
+
+/* The control status byte of each machine looks like ... */
+#define SM_STATE               0xf0    /* Bit 7.. 4:   State which shall be loaded */
+#define SM_LOAD                        BIT_3S  /* Load the SM with SM_STATE */
+#define SM_TEST_ON             BIT_2S  /* Switch on SM Test Mode */
+#define SM_TEST_OFF            BIT_1S  /* Go off the Test Mode */
+#define SM_STEP                        BIT_0S  /* Step the State Machine */
+/* The encoding of the states is not supported by the Diagnostics Tool */
+
+/*     Q_T2                    32 bit  Test Register 2 */
+                                                               /* Bit 31.. 8:  reserved */
+#define T2_AC_T_ON             BIT_7   /* Address Counter Test Mode on */
+#define T2_AC_T_OFF            BIT_6   /* Address Counter Test Mode off */
+#define T2_BC_T_ON             BIT_5   /* Byte Counter Test Mode on */
+#define T2_BC_T_OFF            BIT_4   /* Byte Counter Test Mode off */
+#define T2_STEP04              BIT_3   /* Inc AC/Dec BC by 4 */
+#define T2_STEP03              BIT_2   /* Inc AC/Dec BC by 3 */
+#define T2_STEP02              BIT_1   /* Inc AC/Dec BC by 2 */
+#define T2_STEP01              BIT_0   /* Inc AC/Dec BC by 1 */
+
+/*     Q_T3                    32 bit  Test Register 3 */
+                                                               /* Bit 31.. 7:  reserved */
+#define T3_MUX_MSK             (7<<4)  /* Bit  6.. 4:  Mux Position */
+                                                               /* Bit  3:      reserved */
+#define T3_VRAM_MSK            7               /* Bit  2.. 0:  Virtual RAM Buffer Address */
+
+/* RAM Buffer Register Offsets, use RB_ADDR(Queue, Offs) to access */
+/*     RB_START                32 bit  RAM Buffer Start Address */
+/*     RB_END                  32 bit  RAM Buffer End Address */
+/*     RB_WP                   32 bit  RAM Buffer Write Pointer */
+/*     RB_RP                   32 bit  RAM Buffer Read Pointer */
+/*     RB_RX_UTPP              32 bit  Rx Upper Threshold, Pause Pack */
+/*     RB_RX_LTPP              32 bit  Rx Lower Threshold, Pause Pack */
+/*     RB_RX_UTHP              32 bit  Rx Upper Threshold, High Prio */
+/*     RB_RX_LTHP              32 bit  Rx Lower Threshold, High Prio */
+/*     RB_PC                   32 bit  RAM Buffer Packet Counter */
+/*     RB_LEV                  32 bit  RAM Buffer Level Register */
+                               /* Bit 31..19:  reserved */
+#define RB_MSK 0x0007ffff      /* Bit 18.. 0:  RAM Buffer Pointer Bits */
+
+/*     RB_TST2                  8 bit  RAM Buffer Test Register 2 */
+                                                               /* Bit 7.. 4:   reserved */
+#define RB_PC_DEC              BIT_3S  /* Packet Counter Decrem */
+#define RB_PC_T_ON             BIT_2S  /* Packet Counter Test On */
+#define RB_PC_T_OFF            BIT_1S  /* Packet Counter Tst Off */
+#define RB_PC_INC              BIT_0S  /* Packet Counter Increm */
+
+/*     RB_TST1                  8 bit  RAM Buffer Test Register 1 */
+                                                       /* Bit 7:       reserved */
+#define RB_WP_T_ON             BIT_6S  /* Write Pointer Test On */
+#define RB_WP_T_OFF            BIT_5S  /* Write Pointer Test Off */
+#define RB_WP_INC              BIT_4S  /* Write Pointer Increm */
+                                                               /* Bit 3:       reserved */
+#define RB_RP_T_ON             BIT_2S  /* Read Pointer Test On */
+#define RB_RP_T_OFF            BIT_1S  /* Read Pointer Test Off */
+#define RB_RP_DEC              BIT_0S  /* Read Pointer Decrement */
+
+/*     RB_CTRL                  8 bit  RAM Buffer Control Register */
+                                                               /* Bit 7.. 6:   reserved */
+#define RB_ENA_STFWD   BIT_5S  /* Enable  Store & Forward */
+#define RB_DIS_STFWD   BIT_4S  /* Disable Store & Forward */
+#define RB_ENA_OP_MD   BIT_3S  /* Enable  Operation Mode */
+#define RB_DIS_OP_MD   BIT_2S  /* Disable Operation Mode */
+#define RB_RST_CLR             BIT_1S  /* Clear RAM Buf STM Reset */
+#define RB_RST_SET             BIT_0S  /* Set   RAM Buf STM Reset */
+
+
+/* Receive and Transmit MAC FIFO Registers (GENESIS only) */
+
+/*     RX_MFF_EA               32 bit  Receive MAC FIFO End Address */
+/*     RX_MFF_WP               32 bit  Receive MAC FIFO Write Pointer */
+/*     RX_MFF_RP               32 bit  Receive MAC FIFO Read Pointer */
+/*     RX_MFF_PC               32 bit  Receive MAC FIFO Packet Counter */
+/*     RX_MFF_LEV              32 bit  Receive MAC FIFO Level */
+/*     TX_MFF_EA               32 bit  Transmit MAC FIFO End Address */
+/*     TX_MFF_WP               32 bit  Transmit MAC FIFO Write Pointer */
+/*     TX_MFF_WSP              32 bit  Transmit MAC FIFO WR Shadow Pointer */
+/*     TX_MFF_RP               32 bit  Transmit MAC FIFO Read Pointer */
+/*     TX_MFF_PC               32 bit  Transmit MAC FIFO Packet Cnt */
+/*     TX_MFF_LEV              32 bit  Transmit MAC FIFO Level */
+                                                               /* Bit 31.. 6:  reserved */
+#define MFF_MSK                        0x007fL /* Bit  5.. 0:  MAC FIFO Address/Ptr Bits */
+
+/*     RX_MFF_CTRL1    16 bit  Receive MAC FIFO Control Reg 1 */
+                                                               /* Bit 15..14:  reserved */
+#define MFF_ENA_RDY_PAT        BIT_13S         /* Enable  Ready Patch */
+#define MFF_DIS_RDY_PAT        BIT_12S         /* Disable Ready Patch */
+#define MFF_ENA_TIM_PAT        BIT_11S         /* Enable  Timing Patch */
+#define MFF_DIS_TIM_PAT        BIT_10S         /* Disable Timing Patch */
+#define MFF_ENA_ALM_FUL        BIT_9S          /* Enable  AlmostFull Sign */
+#define MFF_DIS_ALM_FUL        BIT_8S          /* Disable AlmostFull Sign */
+#define MFF_ENA_PAUSE  BIT_7S          /* Enable  Pause Signaling */
+#define MFF_DIS_PAUSE  BIT_6S          /* Disable Pause Signaling */
+#define MFF_ENA_FLUSH  BIT_5S          /* Enable  Frame Flushing */
+#define MFF_DIS_FLUSH  BIT_4S          /* Disable Frame Flushing */
+#define MFF_ENA_TIST   BIT_3S          /* Enable  Time Stamp Gener */
+#define MFF_DIS_TIST   BIT_2S          /* Disable Time Stamp Gener */
+#define MFF_CLR_INTIST BIT_1S          /* Clear IRQ No Time Stamp */
+#define MFF_CLR_INSTAT BIT_0S          /* Clear IRQ No Status */
+
+#define MFF_RX_CTRL_DEF MFF_ENA_TIM_PAT
+
+/*     TX_MFF_CTRL1    16 bit  Transmit MAC FIFO Control Reg 1 */
+#define MFF_CLR_PERR   BIT_15S         /* Clear Parity Error IRQ */
+                                                               /* Bit 14:      reserved */
+#define MFF_ENA_PKT_REC        BIT_13S         /* Enable  Packet Recovery */
+#define MFF_DIS_PKT_REC BIT_12S                /* Disable Packet Recovery */
+/*     MFF_ENA_TIM_PAT  (see RX_MFF_CTRL1) Bit 11:     Enable  Timing Patch */
+/*     MFF_DIS_TIM_PAT  (see RX_MFF_CTRL1) Bit 10:     Disable Timing Patch */
+/*     MFF_ENA_ALM_FUL  (see RX_MFF_CTRL1) Bit  9:     Enable  Almost Full Sign */
+/*     MFF_DIS_ALM_FUL  (see RX_MFF_CTRL1) Bit  8:     Disable Almost Full Sign */
+#define MFF_ENA_W4E            BIT_7S          /* Enable  Wait for Empty */
+#define MFF_DIS_W4E            BIT_6S          /* Disable Wait for Empty */
+/*     MFF_ENA_FLUSH    (see RX_MFF_CTRL1) Bit  5:     Enable  Frame Flushing */
+/*     MFF_DIS_FLUSH    (see RX_MFF_CTRL1) Bit  4:     Disable Frame Flushing */
+#define MFF_ENA_LOOPB  BIT_3S          /* Enable  Loopback */
+#define MFF_DIS_LOOPB  BIT_2S          /* Disable Loopback */
+#define MFF_CLR_MAC_RST        BIT_1S          /* Clear XMAC Reset */
+#define MFF_SET_MAC_RST        BIT_0S          /* Set   XMAC Reset */
+
+#define MFF_TX_CTRL_DEF        (MFF_ENA_PKT_REC | MFF_ENA_TIM_PAT | MFF_ENA_FLUSH)
+
+/*     RX_MFF_TST2              8 bit  Receive MAC FIFO Test Register 2 */
+/*     TX_MFF_TST2              8 bit  Transmit MAC FIFO Test Register 2 */
+                                                               /* Bit 7:       reserved */
+#define MFF_WSP_T_ON   BIT_6S  /* Tx: Write Shadow Ptr TestOn */
+#define MFF_WSP_T_OFF  BIT_5S  /* Tx: Write Shadow Ptr TstOff */
+#define MFF_WSP_INC            BIT_4S  /* Tx: Write Shadow Ptr Increment */
+#define MFF_PC_DEC             BIT_3S  /* Packet Counter Decrement */
+#define MFF_PC_T_ON            BIT_2S  /* Packet Counter Test On */
+#define MFF_PC_T_OFF   BIT_1S  /* Packet Counter Test Off */
+#define MFF_PC_INC             BIT_0S  /* Packet Counter Increment */
+
+/*     RX_MFF_TST1              8 bit  Receive MAC FIFO Test Register 1 */
+/*     TX_MFF_TST1              8 bit  Transmit MAC FIFO Test Register 1 */
+                                       /* Bit 7:       reserved */
+#define MFF_WP_T_ON            BIT_6S  /* Write Pointer Test On */
+#define MFF_WP_T_OFF   BIT_5S  /* Write Pointer Test Off */
+#define MFF_WP_INC             BIT_4S  /* Write Pointer Increm */
+                                                       /* Bit 3:       reserved */
+#define MFF_RP_T_ON            BIT_2S  /* Read Pointer Test On */
+#define MFF_RP_T_OFF   BIT_1S  /* Read Pointer Test Off */
+#define MFF_RP_DEC             BIT_0S  /* Read Pointer Decrement */
+
+/*     RX_MFF_CTRL2     8 bit  Receive MAC FIFO Control Reg 2 */
+/*     TX_MFF_CTRL2     8 bit  Transmit MAC FIFO Control Reg 2 */
+                                                               /* Bit 7..4:    reserved */
+#define MFF_ENA_OP_MD  BIT_3S  /* Enable  Operation Mode */
+#define MFF_DIS_OP_MD  BIT_2S  /* Disable Operation Mode */
+#define MFF_RST_CLR            BIT_1S  /* Clear MAC FIFO Reset */
+#define MFF_RST_SET            BIT_0S  /* Set   MAC FIFO Reset */
+
+
+/*     Link LED Counter Registers (GENESIS only) */
+
+/*     RX_LED_CTRL              8 bit  Receive LED Cnt Control Reg */
+/*     TX_LED_CTRL              8 bit  Transmit LED Cnt Control Reg */
+/*     LNK_SYNC_CTRL    8 bit  Link Sync Cnt Control Register */
+                                                       /* Bit 7.. 3:   reserved */
+#define LED_START              BIT_2S  /* Start Timer */
+#define LED_STOP               BIT_1S  /* Stop Timer */
+#define LED_STATE              BIT_0S  /* Rx/Tx: LED State, 1=LED on */
+#define LED_CLR_IRQ            BIT_0S  /* Lnk:         Clear Link IRQ */
+
+/*     RX_LED_TST               8 bit  Receive LED Cnt Test Register */
+/*     TX_LED_TST               8 bit  Transmit LED Cnt Test Register */
+/*     LNK_SYNC_TST     8 bit  Link Sync Cnt Test Register */
+                                                       /* Bit 7.. 3:   reserved */
+#define LED_T_ON               BIT_2S  /* LED Counter Test mode On */
+#define LED_T_OFF              BIT_1S  /* LED Counter Test mode Off */
+#define LED_T_STEP             BIT_0S  /* LED Counter Step */
+
+/*     LNK_LED_REG              8 bit  Link LED Register */
+                                                               /* Bit 7.. 6:   reserved */
+#define LED_BLK_ON             BIT_5S  /* Link LED Blinking On */
+#define LED_BLK_OFF            BIT_4S  /* Link LED Blinking Off */
+#define LED_SYNC_ON            BIT_3S  /* Use Sync Wire to switch LED */
+#define LED_SYNC_OFF   BIT_2S  /* Disable Sync Wire Input */
+#define LED_ON                 BIT_1S  /* switch LED on */
+#define LED_OFF                        BIT_0S  /* switch LED off */
+
+/*     Receive and Transmit GMAC FIFO Registers (YUKON only) */
+
+/*     RX_GMF_EA               32 bit  Rx GMAC FIFO End Address */
+/*     RX_GMF_AF_THR   32 bit  Rx GMAC FIFO Almost Full Thresh. */
+/*     RX_GMF_WP               32 bit  Rx GMAC FIFO Write Pointer */
+/*     RX_GMF_WLEV             32 bit  Rx GMAC FIFO Write Level */
+/*     RX_GMF_RP               32 bit  Rx GMAC FIFO Read Pointer */
+/*     RX_GMF_RLEV             32 bit  Rx GMAC FIFO Read Level */
+/*     TX_GMF_EA               32 bit  Tx GMAC FIFO End Address */
+/*     TX_GMF_AE_THR   32 bit  Tx GMAC FIFO Almost Empty Thresh.*/
+/*     TX_GMF_WP               32 bit  Tx GMAC FIFO Write Pointer */
+/*     TX_GMF_WSP              32 bit  Tx GMAC FIFO Write Shadow Ptr. */
+/*     TX_GMF_WLEV             32 bit  Tx GMAC FIFO Write Level */
+/*     TX_GMF_RP               32 bit  Tx GMAC FIFO Read Pointer */
+/*     TX_GMF_RSTP             32 bit  Tx GMAC FIFO Restart Pointer */
+/*     TX_GMF_RLEV             32 bit  Tx GMAC FIFO Read Level */
+
+/*     RX_GMF_CTRL_T   32 bit  Rx GMAC FIFO Control/Test */
+                                               /* Bits 31..15: reserved */
+#define GMF_WP_TST_ON  BIT_14          /* Write Pointer Test On */
+#define GMF_WP_TST_OFF BIT_13          /* Write Pointer Test Off */
+#define GMF_WP_STEP            BIT_12          /* Write Pointer Step/Increment */
+                                               /* Bit 11:      reserved */
+#define GMF_RP_TST_ON  BIT_10          /* Read Pointer Test On */
+#define GMF_RP_TST_OFF BIT_9           /* Read Pointer Test Off */
+#define GMF_RP_STEP            BIT_8           /* Read Pointer Step/Increment */
+#define GMF_RX_F_FL_ON BIT_7           /* Rx FIFO Flush Mode On */
+#define GMF_RX_F_FL_OFF        BIT_6           /* Rx FIFO Flush Mode Off */
+#define GMF_CLI_RX_FO  BIT_5           /* Clear IRQ Rx FIFO Overrun */
+#define GMF_CLI_RX_FC  BIT_4           /* Clear IRQ Rx Frame Complete */
+#define GMF_OPER_ON            BIT_3           /* Operational Mode On */
+#define GMF_OPER_OFF   BIT_2           /* Operational Mode Off */
+#define GMF_RST_CLR            BIT_1           /* Clear GMAC FIFO Reset */
+#define GMF_RST_SET            BIT_0           /* Set   GMAC FIFO Reset */
+
+/*     TX_GMF_CTRL_T   32 bit  Tx GMAC FIFO Control/Test */
+                                               /* Bits 31..19: reserved */
+#define GMF_WSP_TST_ON BIT_18          /* Write Shadow Pointer Test On */
+#define GMF_WSP_TST_OFF        BIT_17          /* Write Shadow Pointer Test Off */
+#define GMF_WSP_STEP   BIT_16          /* Write Shadow Pointer Step/Increment */
+                                               /* Bits 15..7: same as for RX_GMF_CTRL_T */
+#define GMF_CLI_TX_FU  BIT_6           /* Clear IRQ Tx FIFO Underrun */
+#define GMF_CLI_TX_FC  BIT_5           /* Clear IRQ Tx Frame Complete */
+#define GMF_CLI_TX_PE  BIT_4           /* Clear IRQ Tx Parity Error */
+                                               /* Bits 3..0: same as for RX_GMF_CTRL_T */
+
+#define GMF_RX_CTRL_DEF                (GMF_OPER_ON | GMF_RX_F_FL_ON)
+#define GMF_TX_CTRL_DEF                GMF_OPER_ON
+
+#define RX_GMF_FL_THR_DEF      0x0a    /* Rx GMAC FIFO Flush Threshold default */
+
+/*     GMAC_TI_ST_CTRL  8 bit  Time Stamp Timer Ctrl Reg (YUKON only) */
+                                                               /* Bit 7.. 3:   reserved */
+#define GMT_ST_START   BIT_2S          /* Start Time Stamp Timer */
+#define GMT_ST_STOP            BIT_1S          /* Stop  Time Stamp Timer */
+#define GMT_ST_CLR_IRQ BIT_0S          /* Clear Time Stamp Timer IRQ */
+
+/*     GMAC_CTRL               32 bit  GMAC Control Reg (YUKON only) */
+                                               /* Bits 31.. 8: reserved */
+#define GMC_H_BURST_ON BIT_7           /* Half Duplex Burst Mode On */
+#define GMC_H_BURST_OFF        BIT_6           /* Half Duplex Burst Mode Off */
+#define GMC_F_LOOPB_ON BIT_5           /* FIFO Loopback On */
+#define GMC_F_LOOPB_OFF        BIT_4           /* FIFO Loopback Off */
+#define GMC_PAUSE_ON   BIT_3           /* Pause On */
+#define GMC_PAUSE_OFF  BIT_2           /* Pause Off */
+#define GMC_RST_CLR            BIT_1           /* Clear GMAC Reset */
+#define GMC_RST_SET            BIT_0           /* Set   GMAC Reset */
+
+/*     GPHY_CTRL               32 bit  GPHY Control Reg (YUKON only) */
+                                               /* Bits 31..29: reserved */
+#define GPC_SEL_BDT            BIT_28  /* Select Bi-Dir. Transfer for MDC/MDIO */
+#define GPC_INT_POL_HI BIT_27  /* IRQ Polarity is Active HIGH */
+#define GPC_75_OHM             BIT_26  /* Use 75 Ohm Termination instead of 50 */
+#define GPC_DIS_FC             BIT_25  /* Disable Automatic Fiber/Copper Detection */
+#define GPC_DIS_SLEEP  BIT_24  /* Disable Energy Detect */
+#define GPC_HWCFG_M_3  BIT_23  /* HWCFG_MODE[3] */
+#define GPC_HWCFG_M_2  BIT_22  /* HWCFG_MODE[2] */
+#define GPC_HWCFG_M_1  BIT_21  /* HWCFG_MODE[1] */
+#define GPC_HWCFG_M_0  BIT_20  /* HWCFG_MODE[0] */
+#define GPC_ANEG_0             BIT_19  /* ANEG[0] */
+#define GPC_ENA_XC             BIT_18  /* Enable MDI crossover */
+#define GPC_DIS_125            BIT_17  /* Disable 125 MHz clock */
+#define GPC_ANEG_3             BIT_16  /* ANEG[3] */
+#define GPC_ANEG_2             BIT_15  /* ANEG[2] */
+#define GPC_ANEG_1             BIT_14  /* ANEG[1] */
+#define GPC_ENA_PAUSE  BIT_13  /* Enable Pause (SYM_OR_REM) */
+#define GPC_PHYADDR_4  BIT_12  /* Bit 4 of Phy Addr */
+#define GPC_PHYADDR_3  BIT_11  /* Bit 3 of Phy Addr */
+#define GPC_PHYADDR_2  BIT_10  /* Bit 2 of Phy Addr */
+#define GPC_PHYADDR_1  BIT_9   /* Bit 1 of Phy Addr */
+#define GPC_PHYADDR_0  BIT_8   /* Bit 0 of Phy Addr */
+                                               /* Bits  7..2:  reserved */
+#define GPC_RST_CLR            BIT_1   /* Clear GPHY Reset */
+#define GPC_RST_SET            BIT_0   /* Set   GPHY Reset */
+
+#define GPC_HWCFG_GMII_COP     (GPC_HWCFG_M_3 | GPC_HWCFG_M_2 | \
+                                                        GPC_HWCFG_M_1 | GPC_HWCFG_M_0)
+
+#define GPC_HWCFG_GMII_FIB     (                                GPC_HWCFG_M_2 | \
+                                                        GPC_HWCFG_M_1 | GPC_HWCFG_M_0)
+
+#define GPC_ANEG_ADV_ALL_M     (GPC_ANEG_3 | GPC_ANEG_2 | \
+                                                        GPC_ANEG_1 | GPC_ANEG_0)
+
+/* forced speed and duplex mode (don't mix with other ANEG bits) */
+#define GPC_FRC10MBIT_HALF     0
+#define GPC_FRC10MBIT_FULL     GPC_ANEG_0
+#define GPC_FRC100MBIT_HALF    GPC_ANEG_1
+#define GPC_FRC100MBIT_FULL    (GPC_ANEG_0 | GPC_ANEG_1)
+
+/* auto-negotiation with limited advertised speeds */
+/* mix only with master/slave settings (for copper) */
+#define GPC_ADV_1000_HALF      GPC_ANEG_2
+#define GPC_ADV_1000_FULL      GPC_ANEG_3
+#define GPC_ADV_ALL                    (GPC_ANEG_2 | GPC_ANEG_3)
+
+/* master/slave settings */
+/* only for copper with 1000 Mbps */
+#define GPC_FORCE_MASTER       0
+#define GPC_FORCE_SLAVE                GPC_ANEG_0
+#define GPC_PREF_MASTER                GPC_ANEG_1
+#define GPC_PREF_SLAVE         (GPC_ANEG_1 | GPC_ANEG_0)
+
+/*     GMAC_IRQ_SRC     8 bit  GMAC Interrupt Source Reg (YUKON only) */
+/*     GMAC_IRQ_MSK     8 bit  GMAC Interrupt Mask   Reg (YUKON only) */
+#define GM_IS_TX_CO_OV BIT_5           /* Transmit Counter Overflow IRQ */
+#define GM_IS_RX_CO_OV BIT_4           /* Receive Counter Overflow IRQ */
+#define GM_IS_TX_FF_UR BIT_3           /* Transmit FIFO Underrun */
+#define GM_IS_TX_COMPL BIT_2           /* Frame Transmission Complete */
+#define GM_IS_RX_FF_OR BIT_1           /* Receive FIFO Overrun */
+#define GM_IS_RX_COMPL BIT_0           /* Frame Reception Complete */
+
+#define GMAC_DEF_MSK   (GM_IS_TX_CO_OV | GM_IS_RX_CO_OV | \
+                                               GM_IS_TX_FF_UR)
+
+/*     GMAC_LINK_CTRL  16 bit  GMAC Link Control Reg (YUKON only) */
+                                               /* Bits 15.. 2: reserved */
+#define GMLC_RST_CLR   BIT_1S          /* Clear GMAC Link Reset */
+#define GMLC_RST_SET   BIT_0S          /* Set   GMAC Link Reset */
+
+
+/*     WOL_CTRL_STAT   16 bit  WOL Control/Status Reg */
+#define WOL_CTL_LINK_CHG_OCC                   BIT_15S
+#define WOL_CTL_MAGIC_PKT_OCC                  BIT_14S
+#define WOL_CTL_PATTERN_OCC                            BIT_13S
+
+#define WOL_CTL_CLEAR_RESULT                   BIT_12S
+
+#define WOL_CTL_ENA_PME_ON_LINK_CHG            BIT_11S
+#define WOL_CTL_DIS_PME_ON_LINK_CHG            BIT_10S
+#define WOL_CTL_ENA_PME_ON_MAGIC_PKT   BIT_9S
+#define WOL_CTL_DIS_PME_ON_MAGIC_PKT   BIT_8S
+#define WOL_CTL_ENA_PME_ON_PATTERN             BIT_7S
+#define WOL_CTL_DIS_PME_ON_PATTERN             BIT_6S
+
+#define WOL_CTL_ENA_LINK_CHG_UNIT              BIT_5S
+#define WOL_CTL_DIS_LINK_CHG_UNIT              BIT_4S
+#define WOL_CTL_ENA_MAGIC_PKT_UNIT             BIT_3S
+#define WOL_CTL_DIS_MAGIC_PKT_UNIT             BIT_2S
+#define WOL_CTL_ENA_PATTERN_UNIT               BIT_1S
+#define WOL_CTL_DIS_PATTERN_UNIT               BIT_0S
+
+#define WOL_CTL_DEFAULT                                \
+       (WOL_CTL_DIS_PME_ON_LINK_CHG |  \
+       WOL_CTL_DIS_PME_ON_PATTERN |    \
+       WOL_CTL_DIS_PME_ON_MAGIC_PKT |  \
+       WOL_CTL_DIS_LINK_CHG_UNIT |             \
+       WOL_CTL_DIS_PATTERN_UNIT |              \
+       WOL_CTL_DIS_MAGIC_PKT_UNIT)
+
+/*     WOL_MATCH_CTL    8 bit  WOL Match Control Reg */
+#define WOL_CTL_PATT_ENA(x)                            (BIT_0 << (x))
+
+#define SK_NUM_WOL_PATTERN             7
+#define SK_PATTERN_PER_WORD            4
+#define SK_BITMASK_PATTERN             7
+#define SK_POW_PATTERN_LENGTH  128
+
+#define WOL_LENGTH_MSK         0x7f
+#define WOL_LENGTH_SHIFT       8
+
+
+/* Receive and Transmit Descriptors ******************************************/
+
+/* Transmit Descriptor struct */
+typedef        struct s_HwTxd {
+       SK_U32 volatile TxCtrl; /* Transmit Buffer Control Field */
+       SK_U32  TxNext;                 /* Physical Address Pointer to the next TxD */
+       SK_U32  TxAdrLo;                /* Physical Tx Buffer Address lower dword */
+       SK_U32  TxAdrHi;                /* Physical Tx Buffer Address upper dword */
+       SK_U32  TxStat;                 /* Transmit Frame Status Word */
+#ifndef        SK_USE_REV_DESC
+       SK_U16  TxTcpOffs;              /* TCP Checksum Calculation Start Value */
+       SK_U16  TxRes1;                 /* 16 bit reserved field */
+       SK_U16  TxTcpWp;                /* TCP Checksum Write Position */
+       SK_U16  TxTcpSp;                /* TCP Checksum Calculation Start Position */
+#else  /* SK_USE_REV_DESC */
+       SK_U16  TxRes1;                 /* 16 bit reserved field */
+       SK_U16  TxTcpOffs;              /* TCP Checksum Calculation Start Value */
+       SK_U16  TxTcpSp;                /* TCP Checksum Calculation Start Position */
+       SK_U16  TxTcpWp;                /* TCP Checksum Write Position */
+#endif /* SK_USE_REV_DESC */
+       SK_U32  TxRes2;                 /* 32 bit reserved field */
+} SK_HWTXD;
+
+/* Receive Descriptor struct */
+typedef        struct s_HwRxd {
+       SK_U32 volatile RxCtrl; /* Receive Buffer Control Field */
+       SK_U32  RxNext;                 /* Physical Address Pointer to the next RxD */
+       SK_U32  RxAdrLo;                /* Physical Rx Buffer Address lower dword */
+       SK_U32  RxAdrHi;                /* Physical Rx Buffer Address upper dword */
+       SK_U32  RxStat;                 /* Receive Frame Status Word */
+       SK_U32  RxTiSt;                 /* Receive Time Stamp (from XMAC on GENESIS) */
+#ifndef        SK_USE_REV_DESC
+       SK_U16  RxTcpSum1;              /* TCP Checksum 1 */
+       SK_U16  RxTcpSum2;              /* TCP Checksum 2 */
+       SK_U16  RxTcpSp1;               /* TCP Checksum Calculation Start Position 1 */
+       SK_U16  RxTcpSp2;               /* TCP Checksum Calculation Start Position 2 */
+#else  /* SK_USE_REV_DESC */
+       SK_U16  RxTcpSum2;              /* TCP Checksum 2 */
+       SK_U16  RxTcpSum1;              /* TCP Checksum 1 */
+       SK_U16  RxTcpSp2;               /* TCP Checksum Calculation Start Position 2 */
+       SK_U16  RxTcpSp1;               /* TCP Checksum Calculation Start Position 1 */
+#endif /* SK_USE_REV_DESC */
+} SK_HWRXD;
+
+/*
+ * Drivers which use the reverse descriptor feature (PCI_OUR_REG_2)
+ * should set the define SK_USE_REV_DESC.
+ * Structures are 'normaly' not endianess dependent. But in
+ * this case the SK_U16 fields are bound to bit positions inside the
+ * descriptor. RxTcpSum1 e.g. must start at bit 0 within the 6.th DWord.
+ * The bit positions inside a DWord are of course endianess dependent and
+ * swaps if the DWord is swapped by the hardware.
+ */
+
+
+/* Descriptor Bit Definition */
+/*     TxCtrl          Transmit Buffer Control Field */
+/*     RxCtrl          Receive  Buffer Control Field */
+#define BMU_OWN                        BIT_31  /* OWN bit: 0=host/1=BMU */
+#define BMU_STF                        BIT_30  /* Start of Frame */
+#define BMU_EOF                        BIT_29  /* End of Frame */
+#define BMU_IRQ_EOB            BIT_28  /* Req "End of Buffer" IRQ */
+#define BMU_IRQ_EOF            BIT_27  /* Req "End of Frame" IRQ */
+/* TxCtrl specific bits */
+#define BMU_STFWD              BIT_26  /* (Tx) Store & Forward Frame */
+#define BMU_NO_FCS             BIT_25  /* (Tx) Disable MAC FCS (CRC) generation */
+#define BMU_SW                 BIT_24  /* (Tx) 1 bit res. for SW use */
+/* RxCtrl specific bits */
+#define BMU_DEV_0              BIT_26  /* (Rx) Transfer data to Dev0 */
+#define BMU_STAT_VAL   BIT_25  /* (Rx) Rx Status Valid */
+#define BMU_TIST_VAL   BIT_24  /* (Rx) Rx TimeStamp Valid */
+                                                               /* Bit 23..16:  BMU Check Opcodes */
+#define BMU_CHECK              (0x55L<<16)     /* Default BMU check */
+#define BMU_TCP_CHECK  (0x56L<<16)     /* Descr with TCP ext */
+#define BMU_UDP_CHECK  (0x57L<<16)     /* Descr with UDP ext (YUKON only) */
+#define BMU_BBC                        0xffffL /* Bit 15.. 0:  Buffer Byte Counter */
+
+/*     TxStat          Transmit Frame Status Word */
+/*     RxStat          Receive Frame Status Word */
+/*
+ *Note: TxStat is reserved for ASIC loopback mode only
+ *
+ *     The Bits of the Status words are defined in xmac_ii.h
+ *     (see XMR_FS bits)
+ */
+
+/* macros ********************************************************************/
+
+/* Receive and Transmit Queues */
+#define Q_R1   0x0000          /* Receive Queue 1 */
+#define Q_R2   0x0080          /* Receive Queue 2 */
+#define Q_XS1  0x0200          /* Synchronous Transmit Queue 1 */
+#define Q_XA1  0x0280          /* Asynchronous Transmit Queue 1 */
+#define Q_XS2  0x0300          /* Synchronous Transmit Queue 2 */
+#define Q_XA2  0x0380          /* Asynchronous Transmit Queue 2 */
+
+/*
+ *     Macro Q_ADDR()
+ *
+ *     Use this macro to access the Receive and Transmit Queue Registers.
+ *
+ * para:
+ *     Queue   Queue to access.
+ *                             Values: Q_R1, Q_R2, Q_XS1, Q_XA1, Q_XS2, and Q_XA2
+ *     Offs    Queue register offset.
+ *                             Values: Q_D, Q_DA_L ... Q_T2, Q_T3
+ *
+ * usage       SK_IN32(pAC, Q_ADDR(Q_R2, Q_BC), pVal)
+ */
+#define Q_ADDR(Queue, Offs)    (B8_Q_REGS + (Queue) + (Offs))
+
+/*
+ *     Macro RB_ADDR()
+ *
+ *     Use this macro to access the RAM Buffer Registers.
+ *
+ * para:
+ *     Queue   Queue to access.
+ *                             Values: Q_R1, Q_R2, Q_XS1, Q_XA1, Q_XS2, and Q_XA2
+ *     Offs    Queue register offset.
+ *                             Values: RB_START, RB_END ... RB_LEV, RB_CTRL
+ *
+ * usage       SK_IN32(pAC, RB_ADDR(Q_R2, RB_RP), pVal)
+ */
+#define RB_ADDR(Queue, Offs)   (B16_RAM_REGS + (Queue) + (Offs))
+
+
+/* MAC Related Registers */
+#define MAC_1          0       /* belongs to the port near the slot */
+#define MAC_2          1       /* belongs to the port far away from the slot */
+
+/*
+ *     Macro MR_ADDR()
+ *
+ *     Use this macro to access a MAC Related Registers inside the ASIC.
+ *
+ * para:
+ *     Mac             MAC to access.
+ *                             Values: MAC_1, MAC_2
+ *     Offs    MAC register offset.
+ *                             Values: RX_MFF_EA, RX_MFF_WP ... LNK_LED_REG,
+ *                                             TX_MFF_EA, TX_MFF_WP ... TX_LED_TST
+ *
+ * usage       SK_IN32(pAC, MR_ADDR(MAC_1, TX_MFF_EA), pVal)
+ */
+#define MR_ADDR(Mac, Offs)     (((Mac) << 7) + (Offs))
+
+#ifdef SK_LITTLE_ENDIAN
+#define XM_WORD_LO     0
+#define XM_WORD_HI     1
+#else  /* !SK_LITTLE_ENDIAN */
+#define XM_WORD_LO     1
+#define XM_WORD_HI     0
+#endif /* !SK_LITTLE_ENDIAN */
+
+
+/*
+ * macros to access the XMAC (GENESIS only)
+ *
+ * XM_IN16(),          to read a 16 bit register (e.g. XM_MMU_CMD)
+ * XM_OUT16(),         to write a 16 bit register (e.g. XM_MMU_CMD)
+ * XM_IN32(),          to read a 32 bit register (e.g. XM_TX_EV_CNT)
+ * XM_OUT32(),         to write a 32 bit register (e.g. XM_TX_EV_CNT)
+ * XM_INADDR(),                to read a network address register (e.g. XM_SRC_CHK)
+ * XM_OUTADDR(),       to write a network address register (e.g. XM_SRC_CHK)
+ * XM_INHASH(),                to read the XM_HSM_CHK register
+ * XM_OUTHASH()                to write the XM_HSM_CHK register
+ *
+ * para:
+ *     Mac             XMAC to access          values: MAC_1 or MAC_2
+ *     IoC             I/O context needed for SK I/O macros
+ *     Reg             XMAC Register to read or write
+ *     (p)Val  Value or pointer to the value which should be read or written
+ *
+ * usage:      XM_OUT16(IoC, MAC_1, XM_MMU_CMD, Value);
+ */
+
+#define XMA(Mac, Reg)                                                                  \
+       ((BASE_XMAC_1 + (Mac) * (BASE_XMAC_2 - BASE_XMAC_1)) | ((Reg) << 1))
+
+#define XM_IN16(IoC, Mac, Reg, pVal)                                   \
+       SK_IN16((IoC), XMA((Mac), (Reg)), (pVal))
+
+#define XM_OUT16(IoC, Mac, Reg, Val)                                   \
+       SK_OUT16((IoC), XMA((Mac), (Reg)), (Val))
+
+#define XM_IN32(IoC, Mac, Reg, pVal) {                                 \
+       SK_IN16((IoC), XMA((Mac), (Reg)),                                       \
+               (SK_U16 SK_FAR*)&((SK_U16 SK_FAR*)(pVal))[XM_WORD_LO]);         \
+       SK_IN16((IoC), XMA((Mac), (Reg+2)),                                     \
+               (SK_U16 SK_FAR*)&((SK_U16 SK_FAR*)(pVal))[XM_WORD_HI]);         \
+}
+
+#define XM_OUT32(IoC, Mac, Reg, Val) {                                                                         \
+       SK_OUT16((IoC), XMA((Mac), (Reg)), (SK_U16)((Val) & 0xffffL));                  \
+       SK_OUT16((IoC), XMA((Mac), (Reg+2)), (SK_U16)(((Val) >> 16) & 0xffffL));\
+}
+
+/* Remember: we are always writing to / reading from LITTLE ENDIAN memory */
+
+#define XM_INADDR(IoC, Mac, Reg, pVal) {                               \
+       SK_U16  Word;                                                                           \
+       SK_U8   *pByte;                                                                         \
+       pByte = (SK_U8 *)&((SK_U8 *)(pVal))[0];                         \
+       SK_IN16((IoC), XMA((Mac), (Reg)), &Word);                       \
+       pByte[0] = (SK_U8)(Word  & 0x00ff);                                     \
+       pByte[1] = (SK_U8)((Word >> 8) & 0x00ff);                       \
+       SK_IN16((IoC), XMA((Mac), (Reg+2)), &Word);                     \
+       pByte[2] = (SK_U8)(Word  & 0x00ff);                                     \
+       pByte[3] = (SK_U8)((Word >> 8) & 0x00ff);                       \
+       SK_IN16((IoC), XMA((Mac), (Reg+4)), &Word);                     \
+       pByte[4] = (SK_U8)(Word  & 0x00ff);                                     \
+       pByte[5] = (SK_U8)((Word >> 8) & 0x00ff);                       \
+}
+
+#define XM_OUTADDR(IoC, Mac, Reg, pVal) {                              \
+       SK_U8   SK_FAR *pByte;                                                          \
+       pByte = (SK_U8 SK_FAR *)&((SK_U8 SK_FAR *)(pVal))[0];   \
+       SK_OUT16((IoC), XMA((Mac), (Reg)), (SK_U16)                     \
+               (((SK_U16)(pByte[0]) & 0x00ff) |                                \
+               (((SK_U16)(pByte[1]) << 8) & 0xff00)));                 \
+       SK_OUT16((IoC), XMA((Mac), (Reg+2)), (SK_U16)           \
+               (((SK_U16)(pByte[2]) & 0x00ff) |                                \
+               (((SK_U16)(pByte[3]) << 8) & 0xff00)));                 \
+       SK_OUT16((IoC), XMA((Mac), (Reg+4)), (SK_U16)           \
+               (((SK_U16)(pByte[4]) & 0x00ff) |                                \
+               (((SK_U16)(pByte[5]) << 8) & 0xff00)));                 \
+}
+
+#define XM_INHASH(IoC, Mac, Reg, pVal) {                               \
+       SK_U16  Word;                                                                           \
+       SK_U8   SK_FAR *pByte;                                                          \
+       pByte = (SK_U8 SK_FAR *)&((SK_U8 SK_FAR *)(pVal))[0];   \
+       SK_IN16((IoC), XMA((Mac), (Reg)), &Word);                       \
+       pByte[0] = (SK_U8)(Word  & 0x00ff);                                     \
+       pByte[1] = (SK_U8)((Word >> 8) & 0x00ff);                       \
+       SK_IN16((IoC), XMA((Mac), (Reg+2)), &Word);                     \
+       pByte[2] = (SK_U8)(Word  & 0x00ff);                                     \
+       pByte[3] = (SK_U8)((Word >> 8) & 0x00ff);                       \
+       SK_IN16((IoC), XMA((Mac), (Reg+4)), &Word);                     \
+       pByte[4] = (SK_U8)(Word  & 0x00ff);                                     \
+       pByte[5] = (SK_U8)((Word >> 8) & 0x00ff);                       \
+       SK_IN16((IoC), XMA((Mac), (Reg+6)), &Word);                     \
+       pByte[6] = (SK_U8)(Word  & 0x00ff);                                     \
+       pByte[7] = (SK_U8)((Word >> 8) & 0x00ff);                       \
+}
+
+#define XM_OUTHASH(IoC, Mac, Reg, pVal) {                              \
+       SK_U8   SK_FAR *pByte;                                                          \
+       pByte = (SK_U8 SK_FAR *)&((SK_U8 SK_FAR *)(pVal))[0];   \
+       SK_OUT16((IoC), XMA((Mac), (Reg)), (SK_U16)                     \
+               (((SK_U16)(pByte[0]) & 0x00ff)|                                 \
+               (((SK_U16)(pByte[1]) << 8) & 0xff00)));                 \
+       SK_OUT16((IoC), XMA((Mac), (Reg+2)), (SK_U16)           \
+               (((SK_U16)(pByte[2]) & 0x00ff)|                                 \
+               (((SK_U16)(pByte[3]) << 8) & 0xff00)));                 \
+       SK_OUT16((IoC), XMA((Mac), (Reg+4)), (SK_U16)           \
+               (((SK_U16)(pByte[4]) & 0x00ff)|                                 \
+               (((SK_U16)(pByte[5]) << 8) & 0xff00)));                 \
+       SK_OUT16((IoC), XMA((Mac), (Reg+6)), (SK_U16)           \
+               (((SK_U16)(pByte[6]) & 0x00ff)|                                 \
+               (((SK_U16)(pByte[7]) << 8) & 0xff00)));                 \
+}
+
+/*
+ * macros to access the GMAC (YUKON only)
+ *
+ * GM_IN16(),          to read  a 16 bit register (e.g. GM_GP_STAT)
+ * GM_OUT16(),         to write a 16 bit register (e.g. GM_GP_CTRL)
+ * GM_IN32(),          to read  a 32 bit register (e.g. GM_)
+ * GM_OUT32(),         to write a 32 bit register (e.g. GM_)
+ * GM_INADDR(),                to read  a network address register (e.g. GM_SRC_ADDR_1L)
+ * GM_OUTADDR(),       to write a network address register (e.g. GM_SRC_ADDR_2L)
+ * GM_INHASH(),                to read  the GM_MC_ADDR_H1 register
+ * GM_OUTHASH()                to write the GM_MC_ADDR_H1 register
+ *
+ * para:
+ *     Mac             GMAC to access          values: MAC_1 or MAC_2
+ *     IoC             I/O context needed for SK I/O macros
+ *     Reg             GMAC Register to read or write
+ *     (p)Val  Value or pointer to the value which should be read or written
+ *
+ * usage:      GM_OUT16(IoC, MAC_1, GM_GP_CTRL, Value);
+ */
+
+#define GMA(Mac, Reg)                                                                  \
+       ((BASE_GMAC_1 + (Mac) * (BASE_GMAC_2 - BASE_GMAC_1)) | (Reg))
+
+#define GM_IN16(IoC, Mac, Reg, pVal)                                   \
+       SK_IN16((IoC), GMA((Mac), (Reg)), (pVal))
+
+#define GM_OUT16(IoC, Mac, Reg, Val)                                   \
+       SK_OUT16((IoC), GMA((Mac), (Reg)), (Val))
+
+#define GM_IN32(IoC, Mac, Reg, pVal) {                                 \
+       SK_IN16((IoC), GMA((Mac), (Reg)),                                       \
+               (SK_U16 SK_FAR*)&((SK_U16 SK_FAR*)(pVal))[XM_WORD_LO]);         \
+       SK_IN16((IoC), GMA((Mac), (Reg+4)),                                     \
+               (SK_U16 SK_FAR*)&((SK_U16 SK_FAR*)(pVal))[XM_WORD_HI]);         \
+}
+
+#define GM_OUT32(IoC, Mac, Reg, Val) {                                                                         \
+       SK_OUT16((IoC), GMA((Mac), (Reg)), (SK_U16)((Val) & 0xffffL));                  \
+       SK_OUT16((IoC), GMA((Mac), (Reg+4)), (SK_U16)(((Val) >> 16) & 0xffffL));\
+}
+
+#define GM_INADDR(IoC, Mac, Reg, pVal) {                               \
+       SK_U16  Word;                                                                           \
+       SK_U8   *pByte;                                                                         \
+       pByte = (SK_U8 *)&((SK_U8 *)(pVal))[0];                         \
+       SK_IN16((IoC), GMA((Mac), (Reg)), &Word);                       \
+       pByte[0] = (SK_U8)(Word  & 0x00ff);                                     \
+       pByte[1] = (SK_U8)((Word >> 8) & 0x00ff);                       \
+       SK_IN16((IoC), GMA((Mac), (Reg+4)), &Word);                     \
+       pByte[2] = (SK_U8)(Word  & 0x00ff);                                     \
+       pByte[3] = (SK_U8)((Word >> 8) & 0x00ff);                       \
+       SK_IN16((IoC), GMA((Mac), (Reg+8)), &Word);                     \
+       pByte[4] = (SK_U8)(Word  & 0x00ff);                                     \
+       pByte[5] = (SK_U8)((Word >> 8) & 0x00ff);                       \
+}
+
+#define GM_OUTADDR(IoC, Mac, Reg, pVal) {                              \
+       SK_U8   SK_FAR *pByte;                                                          \
+       pByte = (SK_U8 SK_FAR *)&((SK_U8 SK_FAR *)(pVal))[0];   \
+       SK_OUT16((IoC), GMA((Mac), (Reg)), (SK_U16)                     \
+               (((SK_U16)(pByte[0]) & 0x00ff) |                                \
+               (((SK_U16)(pByte[1]) << 8) & 0xff00)));                 \
+       SK_OUT16((IoC), GMA((Mac), (Reg+4)), (SK_U16)           \
+               (((SK_U16)(pByte[2]) & 0x00ff) |                                \
+               (((SK_U16)(pByte[3]) << 8) & 0xff00)));                 \
+       SK_OUT16((IoC), GMA((Mac), (Reg+8)), (SK_U16)           \
+               (((SK_U16)(pByte[4]) & 0x00ff) |                                \
+               (((SK_U16)(pByte[5]) << 8) & 0xff00)));                 \
+}
+
+#define GM_INHASH(IoC, Mac, Reg, pVal) {                               \
+       SK_U16  Word;                                                                           \
+       SK_U8   *pByte;                                                                         \
+       pByte = (SK_U8 *)&((SK_U8 *)(pVal))[0];                         \
+       SK_IN16((IoC), GMA((Mac), (Reg)), &Word);                       \
+       pByte[0] = (SK_U8)(Word  & 0x00ff);                                     \
+       pByte[1] = (SK_U8)((Word >> 8) & 0x00ff);                       \
+       SK_IN16((IoC), GMA((Mac), (Reg+4)), &Word);                     \
+       pByte[2] = (SK_U8)(Word  & 0x00ff);                                     \
+       pByte[3] = (SK_U8)((Word >> 8) & 0x00ff);                       \
+       SK_IN16((IoC), GMA((Mac), (Reg+8)), &Word);                     \
+       pByte[4] = (SK_U8)(Word  & 0x00ff);                                     \
+       pByte[5] = (SK_U8)((Word >> 8) & 0x00ff);                       \
+       SK_IN16((IoC), GMA((Mac), (Reg+12)), &Word);            \
+       pByte[6] = (SK_U8)(Word  & 0x00ff);                                     \
+       pByte[7] = (SK_U8)((Word >> 8) & 0x00ff);                       \
+}
+
+#define GM_OUTHASH(IoC, Mac, Reg, pVal) {                              \
+       SK_U8   *pByte;                                                                         \
+       pByte = (SK_U8 *)&((SK_U8 *)(pVal))[0];                         \
+       SK_OUT16((IoC), GMA((Mac), (Reg)), (SK_U16)                     \
+               (((SK_U16)(pByte[0]) & 0x00ff)|                                 \
+               (((SK_U16)(pByte[1]) << 8) & 0xff00)));                 \
+       SK_OUT16((IoC), GMA((Mac), (Reg+4)), (SK_U16)           \
+               (((SK_U16)(pByte[2]) & 0x00ff)|                                 \
+               (((SK_U16)(pByte[3]) << 8) & 0xff00)));                 \
+       SK_OUT16((IoC), GMA((Mac), (Reg+8)), (SK_U16)           \
+               (((SK_U16)(pByte[4]) & 0x00ff)|                                 \
+               (((SK_U16)(pByte[5]) << 8) & 0xff00)));                 \
+       SK_OUT16((IoC), GMA((Mac), (Reg+12)), (SK_U16)          \
+               (((SK_U16)(pByte[6]) & 0x00ff)|                                 \
+               (((SK_U16)(pByte[7]) << 8) & 0xff00)));                 \
+}
+
+/*
+ * Different MAC Types
+ */
+#define SK_MAC_XMAC            0       /* Xaqti XMAC II */
+#define SK_MAC_GMAC            1       /* Marvell GMAC */
+
+/*
+ * Different PHY Types
+ */
+#define SK_PHY_XMAC                    0       /* integrated in XMAC II */
+#define SK_PHY_BCOM                    1       /* Broadcom BCM5400 */
+#define SK_PHY_LONE                    2       /* Level One LXT1000 */
+#define SK_PHY_NAT                     3       /* National DP83891 */
+#define SK_PHY_MARV_COPPER     4       /* Marvell 88E1011S */
+#define SK_PHY_MARV_FIBER      5       /* Marvell 88E1011S working on fiber */
+
+/*
+ * PHY addresses (bits 12..8 of PHY address reg)
+ */
+#define PHY_ADDR_XMAC  (0<<8)
+#define PHY_ADDR_BCOM  (1<<8)
+#define PHY_ADDR_LONE  (3<<8)
+#define PHY_ADDR_NAT   (0<<8)
+
+/* GPHY address (bits 15..11 of SMI control reg) */
+#define PHY_ADDR_MARV  0
+
+/*
+ * macros to access the PHY
+ *
+ * PHY_READ()          read a 16 bit value from the PHY
+ * PHY_WRITE()         write a 16 bit value to the PHY
+ *
+ * para:
+ *     IoC             I/O context needed for SK I/O macros
+ *     pPort   Pointer to port struct for PhyAddr
+ *     Mac             XMAC to access          values: MAC_1 or MAC_2
+ *     PhyReg  PHY Register to read or write
+ *     (p)Val  Value or pointer to the value which should be read or
+ *                     written.
+ *
+ * usage:      PHY_READ(IoC, pPort, MAC_1, PHY_CTRL, Value);
+ * Warning: a PHY_READ on an uninitialized PHY (PHY still in reset) never
+ *          comes back. This is checked in DEBUG mode.
+ */
+#ifndef DEBUG
+#define PHY_READ(IoC, pPort, Mac, PhyReg, pVal) {                                              \
+       SK_U16 Mmu;                                                                                                             \
+                                                                                                                                               \
+       XM_OUT16((IoC), (Mac), XM_PHY_ADDR, (PhyReg) | (pPort)->PhyAddr);       \
+       XM_IN16((IoC), (Mac), XM_PHY_DATA, (pVal));                                                     \
+       if ((pPort)->PhyType != SK_PHY_XMAC) {                                                          \
+               do {                                                                                                                    \
+                       XM_IN16((IoC), (Mac), XM_MMU_CMD, &Mmu);                                        \
+               } while ((Mmu & XM_MMU_PHY_RDY) == 0);                                                  \
+               XM_IN16((IoC), (Mac), XM_PHY_DATA, (pVal));                                             \
+       }                                                                                                                                       \
+}
+#else
+#define PHY_READ(IoC, pPort, Mac, PhyReg, pVal) {                                              \
+       SK_U16 Mmu;                                                                                                             \
+       int __i = 0;                                                                                                            \
+                                                                                                                                               \
+       XM_OUT16((IoC), (Mac), XM_PHY_ADDR, (PhyReg) | (pPort)->PhyAddr);       \
+       XM_IN16((IoC), (Mac), XM_PHY_DATA, (pVal));                                                     \
+       if ((pPort)->PhyType != SK_PHY_XMAC) {                                                          \
+               do {                                                                                                                    \
+                       XM_IN16((IoC), (Mac), XM_MMU_CMD, &Mmu);                                        \
+                       __i++;                                                                                                          \
+                       if (__i > 100000) {                                                                                     \
+                               SK_DBG_PRINTF("*****************************\n");               \
+                               SK_DBG_PRINTF("PHY_READ on uninitialized PHY\n");               \
+                               SK_DBG_PRINTF("*****************************\n");               \
+                               break;                                                                                                  \
+                       }                                                                                                                       \
+               } while ((Mmu & XM_MMU_PHY_RDY) == 0);                                                  \
+               XM_IN16((IoC), (Mac), XM_PHY_DATA, (pVal));                                             \
+       }                                                                                                                                       \
+}
+#endif /* DEBUG */
+
+#define PHY_WRITE(IoC, pPort, Mac, PhyReg, Val) {                                              \
+       SK_U16 Mmu;                                                                                                                     \
+                                                                                                                                               \
+       if ((pPort)->PhyType != SK_PHY_XMAC) {                                                          \
+               do {                                                                                                                    \
+                       XM_IN16((IoC), (Mac), XM_MMU_CMD, &Mmu);                                        \
+               } while ((Mmu & XM_MMU_PHY_BUSY) != 0);                                                 \
+       }                                                                                                                                       \
+       XM_OUT16((IoC), (Mac), XM_PHY_ADDR, (PhyReg) | (pPort)->PhyAddr);       \
+       XM_OUT16((IoC), (Mac), XM_PHY_DATA, (Val));                                                     \
+       if ((pPort)->PhyType != SK_PHY_XMAC) {                                                          \
+               do {                                                                                                                    \
+                       XM_IN16((IoC), (Mac), XM_MMU_CMD, &Mmu);                                        \
+               } while ((Mmu & XM_MMU_PHY_BUSY) != 0);                                                 \
+       }                                                                                                                                       \
+}
+
+/*
+ *     Macro PCI_C()
+ *
+ *     Use this macro to access PCI config register from the I/O space.
+ *
+ * para:
+ *     Addr    PCI configuration register to access.
+ *                     Values: PCI_VENDOR_ID ... PCI_VPD_ADR_REG,
+ *
+ * usage       SK_IN16(pAC, PCI_C(PCI_VENDOR_ID), pVal);
+ */
+#define PCI_C(Addr)    (B7_CFG_SPC + (Addr))   /* PCI Config Space */
+
+/*
+ *     Macro SK_HW_ADDR(Base, Addr)
+ *
+ *     Calculates the effective HW address
+ *
+ * para:
+ *     Base    I/O or memory base address
+ *     Addr    Address offset
+ *
+ * usage:      May be used in SK_INxx and SK_OUTxx macros
+ *             #define SK_IN8(pAC, Addr, pVal) ...\
+ *                     *pVal = (SK_U8)inp(SK_HW_ADDR(pAC->Hw.Iop, Addr)))
+ */
+#ifdef SK_MEM_MAPPED_IO
+#define SK_HW_ADDR(Base, Addr) ((Base) + (Addr))
+#else  /* SK_MEM_MAPPED_IO */
+#define SK_HW_ADDR(Base, Addr) \
+                       ((Base) + (((Addr) & 0x7f) | (((Addr) >> 7 > 0) ? 0x80 : 0)))
+#endif /* SK_MEM_MAPPED_IO */
+
+#define SZ_LONG        (sizeof(SK_U32))
+
+/*
+ *     Macro SK_HWAC_LINK_LED()
+ *
+ *     Use this macro to set the link LED mode.
+ * para:
+ *     pAC             Pointer to adapter context struct
+ *     IoC             I/O context needed for SK I/O macros
+ *  Port       Port number
+ *     Mode    Mode to set for this LED
+ */
+#define SK_HWAC_LINK_LED(pAC, IoC, Port, Mode) \
+       SK_OUT8(IoC, MR_ADDR(Port, LNK_LED_REG), Mode);
+
+
+/* typedefs *******************************************************************/
+
+
+/* function prototypes ********************************************************/
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __INC_SKGEHW_H */
diff --git a/drivers/net/sk98lin/h/skgehwt.h b/drivers/net/sk98lin/h/skgehwt.h
new file mode 100644 (file)
index 0000000..e6b0016
--- /dev/null
@@ -0,0 +1,48 @@
+/******************************************************************************
+ *
+ * Name:       skhwt.h
+ * Project:    Gigabit Ethernet Adapters, Event Scheduler Module
+ * Version:    $Revision: 1.7 $
+ * Date:       $Date: 2003/09/16 12:55:08 $
+ * Purpose:    Defines for the hardware timer functions
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *     (C)Copyright 1998-2002 SysKonnect GmbH.
+ *     (C)Copyright 2002-2003 Marvell.
+ *
+ *     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.
+ *
+ *     The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/*
+ * SKGEHWT.H   contains all defines and types for the timer functions
+ */
+
+#ifndef        _SKGEHWT_H_
+#define _SKGEHWT_H_
+
+/*
+ * SK Hardware Timer
+ * - needed wherever the HWT module is used
+ * - use in Adapters context name pAC->Hwt
+ */
+typedef        struct s_Hwt {
+       SK_U32          TStart; /* HWT start */
+       SK_U32          TStop;  /* HWT stop */
+       int             TActive;        /* HWT: flag : active/inactive */
+} SK_HWT;
+
+extern void SkHwtInit(SK_AC *pAC, SK_IOC Ioc);
+extern void SkHwtStart(SK_AC *pAC, SK_IOC Ioc, SK_U32 Time);
+extern void SkHwtStop(SK_AC *pAC, SK_IOC Ioc);
+extern SK_U32 SkHwtRead(SK_AC *pAC, SK_IOC Ioc);
+extern void SkHwtIsr(SK_AC *pAC, SK_IOC Ioc);
+#endif /* _SKGEHWT_H_ */
diff --git a/drivers/net/sk98lin/h/skgei2c.h b/drivers/net/sk98lin/h/skgei2c.h
new file mode 100644 (file)
index 0000000..d9b6f6d
--- /dev/null
@@ -0,0 +1,210 @@
+/******************************************************************************
+ *
+ * Name:       skgei2c.h
+ * Project:    Gigabit Ethernet Adapters, TWSI-Module
+ * Version:    $Revision: 1.25 $
+ * Date:       $Date: 2003/10/20 09:06:05 $
+ * Purpose:    Special defines for TWSI
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *     (C)Copyright 1998-2002 SysKonnect.
+ *     (C)Copyright 2002-2003 Marvell.
+ *
+ *     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.
+ *
+ *     The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/*
+ * SKGEI2C.H   contains all SK-98xx specific defines for the TWSI handling
+ */
+
+#ifndef _INC_SKGEI2C_H_
+#define _INC_SKGEI2C_H_
+
+/*
+ * Macros to access the B2_I2C_CTRL
+ */
+#define SK_I2C_CTL(IoC, flag, dev, dev_size, reg, burst) \
+       SK_OUT32(IoC, B2_I2C_CTRL,\
+               (flag ? 0x80000000UL : 0x0L) | \
+               (((SK_U32)reg << 16) & I2C_ADDR) | \
+               (((SK_U32)dev << 9) & I2C_DEV_SEL) | \
+               (dev_size & I2C_DEV_SIZE) | \
+               ((burst << 4) & I2C_BURST_LEN))
+
+#define SK_I2C_STOP(IoC) {                             \
+       SK_U32  I2cCtrl;                                \
+       SK_IN32(IoC, B2_I2C_CTRL, &I2cCtrl);            \
+       SK_OUT32(IoC, B2_I2C_CTRL, I2cCtrl | I2C_STOP); \
+}
+
+#define SK_I2C_GET_CTL(IoC, pI2cCtrl)  SK_IN32(IoC, B2_I2C_CTRL, pI2cCtrl)
+
+/*
+ * Macros to access the TWSI SW Registers
+ */
+#define SK_I2C_SET_BIT(IoC, SetBits) {                 \
+       SK_U8   OrgBits;                                \
+       SK_IN8(IoC, B2_I2C_SW, &OrgBits);               \
+       SK_OUT8(IoC, B2_I2C_SW, OrgBits | (SK_U8)(SetBits));    \
+}
+
+#define SK_I2C_CLR_BIT(IoC, ClrBits) {                 \
+       SK_U8   OrgBits;                                \
+       SK_IN8(IoC, B2_I2C_SW, &OrgBits);               \
+       SK_OUT8(IoC, B2_I2C_SW, OrgBits & ~((SK_U8)(ClrBits))); \
+}
+
+#define SK_I2C_GET_SW(IoC, pI2cSw)     SK_IN8(IoC, B2_I2C_SW, pI2cSw)
+
+/*
+ * define the possible sensor states
+ */
+#define        SK_SEN_IDLE             0       /* Idle: sensor not read */
+#define        SK_SEN_VALUE    1       /* Value Read cycle */
+#define        SK_SEN_VALEXT   2       /* Extended Value Read cycle */
+
+/*
+ * Conversion factor to convert read Voltage sensor to milli Volt
+ * Conversion factor to convert read Temperature sensor to 10th degree Celsius
+ */
+#define        SK_LM80_VT_LSB          22      /* 22mV LSB resolution */
+#define        SK_LM80_TEMP_LSB        10      /* 1 degree LSB resolution */
+#define        SK_LM80_TEMPEXT_LSB      5      /* 0.5 degree LSB resolution for ext. val. */
+
+/*
+ * formula: counter = (22500*60)/(rpm * divisor * pulses/2)
+ * assuming: 6500rpm, 4 pulses, divisor 1
+ */
+#define SK_LM80_FAN_FAKTOR     ((22500L*60)/(1*2))
+
+/*
+ * Define sensor management data
+ * Maximum is reached on Genesis copper dual port and Yukon-64
+ * Board specific maximum is in pAC->I2c.MaxSens
+ */
+#define        SK_MAX_SENSORS  8       /* maximal no. of installed sensors */
+#define        SK_MIN_SENSORS  5       /* minimal no. of installed sensors */
+
+/*
+ * To watch the state machine (SM) use the timer in two ways
+ * instead of one as hitherto
+ */
+#define        SK_TIMER_WATCH_SM               0       /* Watch the SM to finish in a spec. time */
+#define        SK_TIMER_NEW_GAUGING    1       /* Start a new gauging when timer expires */
+
+/*
+ * Defines for the individual thresholds
+ */
+
+/* Temperature sensor */
+#define        SK_SEN_TEMP_HIGH_ERR    800     /* Temperature High Err  Threshold */
+#define        SK_SEN_TEMP_HIGH_WARN   700     /* Temperature High Warn Threshold */
+#define        SK_SEN_TEMP_LOW_WARN    100     /* Temperature Low  Warn Threshold */
+#define        SK_SEN_TEMP_LOW_ERR               0     /* Temperature Low  Err  Threshold */
+
+/* VCC which should be 5 V */
+#define        SK_SEN_PCI_5V_HIGH_ERR          5588    /* Voltage PCI High Err  Threshold */
+#define        SK_SEN_PCI_5V_HIGH_WARN         5346    /* Voltage PCI High Warn Threshold */
+#define        SK_SEN_PCI_5V_LOW_WARN          4664    /* Voltage PCI Low  Warn Threshold */
+#define        SK_SEN_PCI_5V_LOW_ERR           4422    /* Voltage PCI Low  Err  Threshold */
+
+/*
+ * VIO may be 5 V or 3.3 V. Initialization takes two parts:
+ * 1. Initialize lowest lower limit and highest higher limit.
+ * 2. After the first value is read correct the upper or the lower limit to
+ *    the appropriate C constant.
+ *
+ * Warning limits are +-5% of the exepected voltage.
+ * Error limits are +-10% of the expected voltage.
+ */
+
+/* Bug fix AF: 16.Aug.2001: Correct the init base of LM80 sensor */
+
+#define        SK_SEN_PCI_IO_5V_HIGH_ERR       5566    /* + 10% V PCI-IO High Err Threshold */
+#define        SK_SEN_PCI_IO_5V_HIGH_WARN      5324    /* +  5% V PCI-IO High Warn Threshold */
+                                       /*              5000    mVolt */
+#define        SK_SEN_PCI_IO_5V_LOW_WARN       4686    /* -  5% V PCI-IO Low Warn Threshold */
+#define        SK_SEN_PCI_IO_5V_LOW_ERR        4444    /* - 10% V PCI-IO Low Err Threshold */
+
+#define        SK_SEN_PCI_IO_RANGE_LIMITER     4000    /* 4000 mV range delimiter */
+
+/* correction values for the second pass */
+#define        SK_SEN_PCI_IO_3V3_HIGH_ERR      3850    /* + 15% V PCI-IO High Err Threshold */
+#define        SK_SEN_PCI_IO_3V3_HIGH_WARN     3674    /* + 10% V PCI-IO High Warn Threshold */
+                                       /*              3300    mVolt */
+#define        SK_SEN_PCI_IO_3V3_LOW_WARN      2926    /* - 10% V PCI-IO Low Warn Threshold */
+#define        SK_SEN_PCI_IO_3V3_LOW_ERR       2772    /* - 15% V PCI-IO Low Err  Threshold */
+
+/*
+ * VDD voltage
+ */
+#define        SK_SEN_VDD_HIGH_ERR             3630    /* Voltage ASIC High Err  Threshold */
+#define        SK_SEN_VDD_HIGH_WARN    3476    /* Voltage ASIC High Warn Threshold */
+#define        SK_SEN_VDD_LOW_WARN             3146    /* Voltage ASIC Low  Warn Threshold */
+#define        SK_SEN_VDD_LOW_ERR              2970    /* Voltage ASIC Low  Err  Threshold */
+
+/*
+ * PHY PLL 3V3 voltage
+ */
+#define        SK_SEN_PLL_3V3_HIGH_ERR         3630    /* Voltage PMA High Err  Threshold */
+#define        SK_SEN_PLL_3V3_HIGH_WARN        3476    /* Voltage PMA High Warn Threshold */
+#define        SK_SEN_PLL_3V3_LOW_WARN         3146    /* Voltage PMA Low  Warn Threshold */
+#define        SK_SEN_PLL_3V3_LOW_ERR          2970    /* Voltage PMA Low  Err  Threshold */
+
+/*
+ * VAUX (YUKON only)
+ */
+#define        SK_SEN_VAUX_3V3_HIGH_ERR        3630    /* Voltage VAUX High Err Threshold */
+#define        SK_SEN_VAUX_3V3_HIGH_WARN       3476    /* Voltage VAUX High Warn Threshold */
+#define        SK_SEN_VAUX_3V3_LOW_WARN        3146    /* Voltage VAUX Low Warn Threshold */
+#define        SK_SEN_VAUX_3V3_LOW_ERR         2970    /* Voltage VAUX Low Err Threshold */
+#define        SK_SEN_VAUX_0V_WARN_ERR            0    /* if VAUX not present */
+#define        SK_SEN_VAUX_RANGE_LIMITER       1000    /* 1000 mV range delimiter */
+
+/*
+ * PHY 2V5 voltage
+ */
+#define        SK_SEN_PHY_2V5_HIGH_ERR         2750    /* Voltage PHY High Err Threshold */
+#define        SK_SEN_PHY_2V5_HIGH_WARN        2640    /* Voltage PHY High Warn Threshold */
+#define        SK_SEN_PHY_2V5_LOW_WARN         2376    /* Voltage PHY Low Warn Threshold */
+#define        SK_SEN_PHY_2V5_LOW_ERR          2222    /* Voltage PHY Low Err Threshold */
+
+/*
+ * ASIC Core 1V5 voltage (YUKON only)
+ */
+#define        SK_SEN_CORE_1V5_HIGH_ERR        1650    /* Voltage ASIC Core High Err Threshold */
+#define        SK_SEN_CORE_1V5_HIGH_WARN       1575    /* Voltage ASIC Core High Warn Threshold */
+#define        SK_SEN_CORE_1V5_LOW_WARN        1425    /* Voltage ASIC Core Low Warn Threshold */
+#define        SK_SEN_CORE_1V5_LOW_ERR         1350    /* Voltage ASIC Core Low Err Threshold */
+
+/*
+ * FAN 1 speed
+ */
+/* assuming: 6500rpm +-15%, 4 pulses,
+ * warning at: 80 %
+ * error at:   70 %
+ * no upper limit
+ */
+#define        SK_SEN_FAN_HIGH_ERR             20000   /* FAN Speed High Err Threshold */
+#define        SK_SEN_FAN_HIGH_WARN    20000   /* FAN Speed High Warn Threshold */
+#define        SK_SEN_FAN_LOW_WARN              5200   /* FAN Speed Low Warn Threshold */
+#define        SK_SEN_FAN_LOW_ERR               4550   /* FAN Speed Low Err Threshold */
+
+/*
+ * Some Voltages need dynamic thresholds
+ */
+#define        SK_SEN_DYN_INIT_NONE             0  /* No dynamic init of thresholds */
+#define        SK_SEN_DYN_INIT_PCI_IO          10  /* Init PCI-IO with new thresholds */
+#define        SK_SEN_DYN_INIT_VAUX            11  /* Init VAUX with new thresholds */
+
+extern int SkLm80ReadSensor(SK_AC *pAC, SK_IOC IoC, SK_SENSOR *pSen);
+#endif /* n_INC_SKGEI2C_H */
diff --git a/drivers/net/sk98lin/h/skgeinit.h b/drivers/net/sk98lin/h/skgeinit.h
new file mode 100644 (file)
index 0000000..143e635
--- /dev/null
@@ -0,0 +1,797 @@
+/******************************************************************************
+ *
+ * Name:       skgeinit.h
+ * Project:    Gigabit Ethernet Adapters, Common Modules
+ * Version:    $Revision: 1.83 $
+ * Date:       $Date: 2003/09/16 14:07:37 $
+ * Purpose:    Structures and prototypes for the GE Init Module
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *     (C)Copyright 1998-2002 SysKonnect.
+ *     (C)Copyright 2002-2003 Marvell.
+ *
+ *     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.
+ *
+ *     The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+#ifndef __INC_SKGEINIT_H_
+#define __INC_SKGEINIT_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/* defines ********************************************************************/
+
+#define SK_TEST_VAL            0x11335577UL
+
+/* modifying Link LED behaviour (used with SkGeLinkLED()) */
+#define SK_LNK_OFF             LED_OFF
+#define SK_LNK_ON              (LED_ON | LED_BLK_OFF | LED_SYNC_OFF)
+#define SK_LNK_BLINK   (LED_ON | LED_BLK_ON  | LED_SYNC_ON)
+#define SK_LNK_PERM            (LED_ON | LED_BLK_OFF | LED_SYNC_ON)
+#define SK_LNK_TST             (LED_ON | LED_BLK_ON  | LED_SYNC_OFF)
+
+/* parameter 'Mode' when calling SK_HWAC_LINK_LED() */
+#define SK_LED_OFF             LED_OFF
+#define SK_LED_ACTIVE  (LED_ON | LED_BLK_OFF | LED_SYNC_OFF)
+#define SK_LED_STANDBY (LED_ON | LED_BLK_ON  | LED_SYNC_OFF)
+
+/* addressing LED Registers in SkGeXmitLED() */
+#define XMIT_LED_INI   0
+#define XMIT_LED_CNT   (RX_LED_VAL - RX_LED_INI)
+#define XMIT_LED_CTRL  (RX_LED_CTRL- RX_LED_INI)
+#define XMIT_LED_TST   (RX_LED_TST - RX_LED_INI)
+
+/* parameter 'Mode' when calling SkGeXmitLED() */
+#define SK_LED_DIS     0
+#define SK_LED_ENA     1
+#define SK_LED_TST     2
+
+/* Counter and Timer constants, for a host clock of 62.5 MHz */
+#define SK_XMIT_DUR            0x002faf08UL    /*  50 ms */
+#define SK_BLK_DUR             0x01dcd650UL    /* 500 ms */
+
+#define SK_DPOLL_DEF   0x00ee6b28UL    /* 250 ms at 62.5 MHz */
+
+#define SK_DPOLL_MAX   0x00ffffffUL    /* 268 ms at 62.5 MHz */
+                                                                               /* 215 ms at 78.12 MHz */
+
+#define SK_FACT_62             100                     /* is given in percent */
+#define SK_FACT_53              85         /* on GENESIS:      53.12 MHz */
+#define SK_FACT_78             125                     /* on YUKON:    78.12 MHz */
+
+/* Timeout values */
+#define SK_MAC_TO_53   72                      /* MAC arbiter timeout */
+#define SK_PKT_TO_53   0x2000          /* Packet arbiter timeout */
+#define SK_PKT_TO_MAX  0xffff          /* Maximum value */
+#define SK_RI_TO_53            36                      /* RAM interface timeout */
+
+#define SK_PHY_ACC_TO  600000          /* PHY access timeout */
+
+/* RAM Buffer High Pause Threshold values */
+#define SK_RB_ULPP             ( 8 * 1024)     /* Upper Level in kB/8 */
+#define SK_RB_LLPP_S   (10 * 1024)     /* Lower Level for small Queues */
+#define SK_RB_LLPP_B   (16 * 1024)     /* Lower Level for big Queues */
+
+#ifndef SK_BMU_RX_WM
+#define SK_BMU_RX_WM   0x600           /* BMU Rx Watermark */
+#endif
+#ifndef SK_BMU_TX_WM
+#define SK_BMU_TX_WM   0x600           /* BMU Tx Watermark */
+#endif
+
+/* XMAC II Rx High Watermark */
+#define SK_XM_RX_HI_WM 0x05aa          /* 1450 */
+
+/* XMAC II Tx Threshold */
+#define SK_XM_THR_REDL 0x01fb          /* .. for redundant link usage */
+#define SK_XM_THR_SL   0x01fb          /* .. for single link adapters */
+#define SK_XM_THR_MULL 0x01fb          /* .. for multiple link usage */
+#define SK_XM_THR_JUMBO        0x03fc          /* .. for jumbo frame usage */
+
+/* values for GIPortUsage */
+#define SK_RED_LINK            1               /* redundant link usage */
+#define SK_MUL_LINK            2               /* multiple link usage */
+#define SK_JUMBO_LINK  3               /* driver uses jumbo frames */
+
+/* Minimum RAM Buffer Rx Queue Size */
+#define SK_MIN_RXQ_SIZE        16              /* 16 kB */
+
+/* Minimum RAM Buffer Tx Queue Size */
+#define SK_MIN_TXQ_SIZE        16              /* 16 kB */
+
+/* Queue Size units */
+#define QZ_UNITS               0x7
+#define QZ_STEP                        8
+
+/* Percentage of queue size from whole memory */
+/* 80 % for receive */
+#define RAM_QUOTA_RX   80L
+/* 0% for sync transfer */
+#define        RAM_QUOTA_SYNC  0L
+/* the rest (20%) is taken for async transfer */
+
+/* Get the rounded queue size in Bytes in 8k steps */
+#define ROUND_QUEUE_SIZE(SizeInBytes)                                  \
+       ((((unsigned long) (SizeInBytes) + (QZ_STEP*1024L)-1) / 1024) & \
+       ~(QZ_STEP-1))
+
+/* Get the rounded queue size in KBytes in 8k steps */
+#define ROUND_QUEUE_SIZE_KB(Kilobytes) \
+       ROUND_QUEUE_SIZE((Kilobytes) * 1024L)
+
+/* Types of RAM Buffer Queues */
+#define SK_RX_SRAM_Q   1       /* small receive queue */
+#define SK_RX_BRAM_Q   2       /* big receive queue */
+#define SK_TX_RAM_Q            3       /* small or big transmit queue */
+
+/* parameter 'Dir' when calling SkGeStopPort() */
+#define SK_STOP_TX     1       /* Stops the transmit path, resets the XMAC */
+#define SK_STOP_RX     2       /* Stops the receive path */
+#define SK_STOP_ALL    3       /* Stops Rx and Tx path, resets the XMAC */
+
+/* parameter 'RstMode' when calling SkGeStopPort() */
+#define SK_SOFT_RST    1       /* perform a software reset */
+#define SK_HARD_RST    2       /* perform a hardware reset */
+
+/* Init Levels */
+#define SK_INIT_DATA   0       /* Init level 0: init data structures */
+#define SK_INIT_IO             1       /* Init level 1: init with IOs */
+#define SK_INIT_RUN            2       /* Init level 2: init for run time */
+
+/* Link Mode Parameter */
+#define SK_LMODE_HALF          1       /* Half Duplex Mode */
+#define SK_LMODE_FULL          2       /* Full Duplex Mode */
+#define SK_LMODE_AUTOHALF      3       /* AutoHalf Duplex Mode */
+#define SK_LMODE_AUTOFULL      4       /* AutoFull Duplex Mode */
+#define SK_LMODE_AUTOBOTH      5       /* AutoBoth Duplex Mode */
+#define SK_LMODE_AUTOSENSE     6       /* configured mode auto sensing */
+#define SK_LMODE_INDETERMINATED        7       /* indeterminated */
+
+/* Auto-negotiation timeout in 100ms granularity */
+#define SK_AND_MAX_TO          6       /* Wait 600 msec before link comes up */
+
+/* Auto-negotiation error codes */
+#define SK_AND_OK                      0       /* no error */
+#define SK_AND_OTHER           1       /* other error than below */
+#define SK_AND_DUP_CAP         2       /* Duplex capabilities error */
+
+
+/* Link Speed Capabilities */
+#define SK_LSPEED_CAP_AUTO                     (1<<0)  /* Automatic resolution */
+#define SK_LSPEED_CAP_10MBPS           (1<<1)  /* 10 Mbps */
+#define SK_LSPEED_CAP_100MBPS          (1<<2)  /* 100 Mbps */
+#define SK_LSPEED_CAP_1000MBPS         (1<<3)  /* 1000 Mbps */
+#define SK_LSPEED_CAP_INDETERMINATED (1<<4) /* indeterminated */
+
+/* Link Speed Parameter */
+#define SK_LSPEED_AUTO                         1       /* Automatic resolution */
+#define SK_LSPEED_10MBPS                       2       /* 10 Mbps */
+#define SK_LSPEED_100MBPS                      3       /* 100 Mbps */
+#define SK_LSPEED_1000MBPS                     4       /* 1000 Mbps */
+#define SK_LSPEED_INDETERMINATED       5       /* indeterminated */
+
+/* Link Speed Current State */
+#define SK_LSPEED_STAT_UNKNOWN         1
+#define SK_LSPEED_STAT_10MBPS          2
+#define SK_LSPEED_STAT_100MBPS                 3
+#define SK_LSPEED_STAT_1000MBPS                4
+#define SK_LSPEED_STAT_INDETERMINATED 5
+
+
+/* Link Capability Parameter */
+#define SK_LMODE_CAP_HALF              (1<<0)  /* Half Duplex Mode */
+#define SK_LMODE_CAP_FULL              (1<<1)  /* Full Duplex Mode */
+#define SK_LMODE_CAP_AUTOHALF  (1<<2)  /* AutoHalf Duplex Mode */
+#define SK_LMODE_CAP_AUTOFULL  (1<<3)  /* AutoFull Duplex Mode */
+#define SK_LMODE_CAP_INDETERMINATED (1<<4) /* indeterminated */
+
+/* Link Mode Current State */
+#define SK_LMODE_STAT_UNKNOWN  1       /* Unknown Duplex Mode */
+#define SK_LMODE_STAT_HALF             2       /* Half Duplex Mode */
+#define SK_LMODE_STAT_FULL             3       /* Full Duplex Mode */
+#define SK_LMODE_STAT_AUTOHALF 4       /* Half Duplex Mode obtained by Auto-Neg */
+#define SK_LMODE_STAT_AUTOFULL 5       /* Full Duplex Mode obtained by Auto-Neg */
+#define SK_LMODE_STAT_INDETERMINATED 6 /* indeterminated */
+
+/* Flow Control Mode Parameter (and capabilities) */
+#define SK_FLOW_MODE_NONE              1       /* No Flow-Control */
+#define SK_FLOW_MODE_LOC_SEND  2       /* Local station sends PAUSE */
+#define SK_FLOW_MODE_SYMMETRIC 3       /* Both stations may send PAUSE */
+#define SK_FLOW_MODE_SYM_OR_REM        4       /* Both stations may send PAUSE or
+                                        * just the remote station may send PAUSE
+                                        */
+#define SK_FLOW_MODE_INDETERMINATED 5  /* indeterminated */
+
+/* Flow Control Status Parameter */
+#define SK_FLOW_STAT_NONE              1       /* No Flow Control */
+#define SK_FLOW_STAT_REM_SEND  2       /* Remote Station sends PAUSE */
+#define SK_FLOW_STAT_LOC_SEND  3       /* Local station sends PAUSE */
+#define SK_FLOW_STAT_SYMMETRIC 4       /* Both station may send PAUSE */
+#define SK_FLOW_STAT_INDETERMINATED 5  /* indeterminated */
+
+/* Master/Slave Mode Capabilities */
+#define SK_MS_CAP_AUTO         (1<<0)  /* Automatic resolution */
+#define SK_MS_CAP_MASTER       (1<<1)  /* This station is master */
+#define SK_MS_CAP_SLAVE                (1<<2)  /* This station is slave */
+#define SK_MS_CAP_INDETERMINATED (1<<3)        /* indeterminated */
+
+/* Set Master/Slave Mode Parameter (and capabilities) */
+#define SK_MS_MODE_AUTO                1       /* Automatic resolution */
+#define SK_MS_MODE_MASTER      2       /* This station is master */
+#define SK_MS_MODE_SLAVE       3       /* This station is slave */
+#define SK_MS_MODE_INDETERMINATED 4    /* indeterminated */
+
+/* Master/Slave Status Parameter */
+#define SK_MS_STAT_UNSET       1       /* The M/S status is not set */
+#define SK_MS_STAT_MASTER      2       /* This station is master */
+#define SK_MS_STAT_SLAVE       3       /* This station is slave */
+#define SK_MS_STAT_FAULT       4       /* M/S resolution failed */
+#define SK_MS_STAT_INDETERMINATED 5    /* indeterminated */
+
+/* parameter 'Mode' when calling SkXmSetRxCmd() */
+#define SK_STRIP_FCS_ON                (1<<0)  /* Enable  FCS stripping of Rx frames */
+#define SK_STRIP_FCS_OFF       (1<<1)  /* Disable FCS stripping of Rx frames */
+#define SK_STRIP_PAD_ON                (1<<2)  /* Enable  pad byte stripping of Rx fr */
+#define SK_STRIP_PAD_OFF       (1<<3)  /* Disable pad byte stripping of Rx fr */
+#define SK_LENERR_OK_ON                (1<<4)  /* Don't chk fr for in range len error */
+#define SK_LENERR_OK_OFF       (1<<5)  /* Check frames for in range len error */
+#define SK_BIG_PK_OK_ON                (1<<6)  /* Don't set Rx Error bit for big frames */
+#define SK_BIG_PK_OK_OFF       (1<<7)  /* Set Rx Error bit for big frames */
+#define SK_SELF_RX_ON          (1<<8)  /* Enable  Rx of own packets */
+#define SK_SELF_RX_OFF         (1<<9)  /* Disable Rx of own packets */
+
+/* parameter 'Para' when calling SkMacSetRxTxEn() */
+#define SK_MAC_LOOPB_ON                (1<<0)  /* Enable  MAC Loopback Mode */
+#define SK_MAC_LOOPB_OFF       (1<<1)  /* Disable MAC Loopback Mode */
+#define SK_PHY_LOOPB_ON                (1<<2)  /* Enable  PHY Loopback Mode */
+#define SK_PHY_LOOPB_OFF       (1<<3)  /* Disable PHY Loopback Mode */
+#define SK_PHY_FULLD_ON                (1<<4)  /* Enable  GMII Full Duplex */
+#define SK_PHY_FULLD_OFF       (1<<5)  /* Disable GMII Full Duplex */
+
+/* States of PState */
+#define SK_PRT_RESET   0       /* the port is reset */
+#define SK_PRT_STOP            1       /* the port is stopped (similar to SW reset) */
+#define SK_PRT_INIT            2       /* the port is initialized */
+#define SK_PRT_RUN             3       /* the port has an active link */
+
+/* PHY power down modes */
+#define PHY_PM_OPERATIONAL_MODE                0       /* PHY operational mode */
+#define PHY_PM_DEEP_SLEEP                      1       /* coma mode --> minimal power */
+#define PHY_PM_IEEE_POWER_DOWN         2       /* IEEE 22.2.4.1.5 compl. power down */
+#define PHY_PM_ENERGY_DETECT           3       /* energy detect */
+#define PHY_PM_ENERGY_DETECT_PLUS      4       /* energy detect plus */
+
+/* Default receive frame limit for Workaround of XMAC Errata */
+#define SK_DEF_RX_WA_LIM       SK_CONSTU64(100)
+
+/* values for GILedBlinkCtrl (LED Blink Control) */
+#define SK_ACT_LED_BLINK       (1<<0)  /* Active LED blinking */
+#define SK_DUP_LED_NORMAL      (1<<1)  /* Duplex LED normal */
+#define SK_LED_LINK100_ON      (1<<2)  /* Link 100M LED on */
+
+/* Link Partner Status */
+#define SK_LIPA_UNKNOWN        0       /* Link partner is in unknown state */
+#define SK_LIPA_MANUAL 1       /* Link partner is in detected manual state */
+#define SK_LIPA_AUTO   2       /* Link partner is in auto-negotiation state */
+
+/* Maximum Restarts before restart is ignored (3Com WA) */
+#define SK_MAX_LRESTART        3       /* Max. 3 times the link is restarted */
+
+/* Max. Auto-neg. timeouts before link detection in sense mode is reset */
+#define SK_MAX_ANEG_TO 10      /* Max. 10 times the sense mode is reset */
+
+/* structures *****************************************************************/
+
+/*
+ * MAC specific functions
+ */
+typedef struct s_GeMacFunc {
+       int  (*pFnMacUpdateStats)(SK_AC *pAC, SK_IOC IoC, unsigned int Port);
+       int  (*pFnMacStatistic)(SK_AC *pAC, SK_IOC IoC, unsigned int Port,
+                                                       SK_U16 StatAddr, SK_U32 SK_FAR *pVal);
+       int  (*pFnMacResetCounter)(SK_AC *pAC, SK_IOC IoC, unsigned int Port);
+       int  (*pFnMacOverflow)(SK_AC *pAC, SK_IOC IoC, unsigned int Port,
+                                                  SK_U16 IStatus, SK_U64 SK_FAR *pVal);
+} SK_GEMACFUNC;
+
+/*
+ * Port Structure
+ */
+typedef        struct s_GePort {
+#ifndef SK_DIAG
+       SK_TIMER        PWaTimer;       /* Workaround Timer */
+       SK_TIMER        HalfDupChkTimer;
+#endif /* SK_DIAG */
+       SK_U32  PPrevShorts;    /* Previous Short Counter checking */
+       SK_U32  PPrevFcs;               /* Previous FCS Error Counter checking */
+       SK_U64  PPrevRx;                /* Previous RxOk Counter checking */
+       SK_U64  PRxLim;                 /* Previous RxOk Counter checking */
+       SK_U64  LastOctets;             /* For half duplex hang check */
+       int             PLinkResCt;             /* Link Restart Counter */
+       int             PAutoNegTimeOut;/* Auto-negotiation timeout current value */
+       int             PAutoNegTOCt;   /* Auto-negotiation Timeout Counter */
+       int             PRxQSize;               /* Port Rx Queue Size in kB */
+       int             PXSQSize;               /* Port Synchronous  Transmit Queue Size in kB */
+       int             PXAQSize;               /* Port Asynchronous Transmit Queue Size in kB */
+       SK_U32  PRxQRamStart;   /* Receive Queue RAM Buffer Start Address */
+       SK_U32  PRxQRamEnd;             /* Receive Queue RAM Buffer End Address */
+       SK_U32  PXsQRamStart;   /* Sync Tx Queue RAM Buffer Start Address */
+       SK_U32  PXsQRamEnd;             /* Sync Tx Queue RAM Buffer End Address */
+       SK_U32  PXaQRamStart;   /* Async Tx Queue RAM Buffer Start Address */
+       SK_U32  PXaQRamEnd;             /* Async Tx Queue RAM Buffer End Address */
+       SK_U32  PRxOverCnt;             /* Receive Overflow Counter */
+       int             PRxQOff;                /* Rx Queue Address Offset */
+       int             PXsQOff;                /* Synchronous Tx Queue Address Offset */
+       int             PXaQOff;                /* Asynchronous Tx Queue Address Offset */
+       int             PhyType;                /* PHY used on this port */
+       int             PState;                 /* Port status (reset, stop, init, run) */
+       SK_U16  PhyId1;                 /* PHY Id1 on this port */
+       SK_U16  PhyAddr;                /* MDIO/MDC PHY address */
+       SK_U16  PIsave;                 /* Saved Interrupt status word */
+       SK_U16  PSsave;                 /* Saved PHY status word */
+       SK_U16  PGmANegAdv;             /* Saved GPhy AutoNegAdvertisment register */
+       SK_BOOL PHWLinkUp;              /* The hardware Link is up (wiring) */
+       SK_BOOL PLinkBroken;    /* Is Link broken ? */
+       SK_BOOL PCheckPar;              /* Do we check for parity errors ? */
+       SK_BOOL HalfDupTimerActive;
+       SK_U8   PLinkCap;               /* Link Capabilities */
+       SK_U8   PLinkModeConf;  /* Link Mode configured */
+       SK_U8   PLinkMode;              /* Link Mode currently used */
+       SK_U8   PLinkModeStatus;/* Link Mode Status */
+       SK_U8   PLinkSpeedCap;  /* Link Speed Capabilities(10/100/1000 Mbps) */
+       SK_U8   PLinkSpeed;             /* configured Link Speed (10/100/1000 Mbps) */
+       SK_U8   PLinkSpeedUsed; /* current Link Speed (10/100/1000 Mbps) */
+       SK_U8   PFlowCtrlCap;   /* Flow Control Capabilities */
+       SK_U8   PFlowCtrlMode;  /* Flow Control Mode */
+       SK_U8   PFlowCtrlStatus;/* Flow Control Status */
+       SK_U8   PMSCap;                 /* Master/Slave Capabilities */
+       SK_U8   PMSMode;                /* Master/Slave Mode */
+       SK_U8   PMSStatus;              /* Master/Slave Status */
+       SK_BOOL PAutoNegFail;   /* Auto-negotiation fail flag */
+       SK_U8   PLipaAutoNeg;   /* Auto-negotiation possible with Link Partner */
+       SK_U8   PCableLen;              /* Cable Length */
+       SK_U8   PMdiPairLen[4]; /* MDI[0..3] Pair Length */
+       SK_U8   PMdiPairSts[4]; /* MDI[0..3] Pair Diagnostic Status */
+       SK_U8   PPhyPowerState; /* PHY current power state */
+       int             PMacColThres;   /* MAC Collision Threshold */
+       int             PMacJamLen;             /* MAC Jam length */
+       int             PMacJamIpgVal;  /* MAC Jam IPG */
+       int             PMacJamIpgData; /* MAC IPG Jam to Data */
+       int             PMacIpgData;    /* MAC Data IPG */
+       SK_BOOL PMacLimit4;             /* reset collision counter and backoff algorithm */
+} SK_GEPORT;
+
+/*
+ * Gigabit Ethernet Initialization Struct
+ * (has to be included in the adapter context)
+ */
+typedef        struct s_GeInit {
+       int                     GIChipId;               /* Chip Identification Number */
+       int                     GIChipRev;              /* Chip Revision Number */
+       SK_U8           GIPciHwRev;             /* PCI HW Revision Number */
+       SK_BOOL         GIGenesis;              /* Genesis adapter ? */
+       SK_BOOL         GIYukon;                /* YUKON-A1/Bx chip */
+       SK_BOOL         GIYukonLite;    /* YUKON-Lite chip */
+       SK_BOOL         GICopperType;   /* Copper Type adapter ? */
+       SK_BOOL         GIPciSlot64;    /* 64-bit PCI Slot */
+       SK_BOOL         GIPciClock66;   /* 66 MHz PCI Clock */
+       SK_BOOL         GIVauxAvail;    /* VAUX available (YUKON) */
+       SK_BOOL         GIYukon32Bit;   /* 32-Bit YUKON adapter */
+       SK_U16          GILedBlinkCtrl; /* LED Blink Control */
+       int                     GIMacsFound;    /* Number of MACs found on this adapter */
+       int                     GIMacType;              /* MAC Type used on this adapter */
+       int                     GIHstClkFact;   /* Host Clock Factor (62.5 / HstClk * 100) */
+       int                     GIPortUsage;    /* Driver Port Usage */
+       int                     GILevel;                /* Initialization Level completed */
+       int                     GIRamSize;              /* The RAM size of the adapter in kB */
+       int                     GIWolOffs;              /* WOL Register Offset (HW-Bug in Rev. A) */
+       SK_U32          GIRamOffs;              /* RAM Address Offset for addr calculation */
+       SK_U32          GIPollTimerVal; /* Descr. Poll Timer Init Val (HstClk ticks) */
+       SK_U32          GIValIrqMask;   /* Value for Interrupt Mask */
+       SK_U32          GITimeStampCnt; /* Time Stamp High Counter (YUKON only) */
+       SK_GEPORT       GP[SK_MAX_MACS];/* Port Dependent Information */
+       SK_GEMACFUNC GIFunc;            /* MAC depedent functions */
+} SK_GEINIT;
+
+/*
+ * Error numbers and messages for skxmac2.c and skgeinit.c
+ */
+#define SKERR_HWI_E001         (SK_ERRBASE_HWINIT)
+#define SKERR_HWI_E001MSG      "SkXmClrExactAddr() has got illegal parameters"
+#define SKERR_HWI_E002         (SKERR_HWI_E001+1)
+#define SKERR_HWI_E002MSG      "SkGeInit(): Level 1 call missing"
+#define SKERR_HWI_E003         (SKERR_HWI_E002+1)
+#define SKERR_HWI_E003MSG      "SkGeInit() called with illegal init Level"
+#define SKERR_HWI_E004         (SKERR_HWI_E003+1)
+#define SKERR_HWI_E004MSG      "SkGeInitPort(): Queue Size illegal configured"
+#define SKERR_HWI_E005         (SKERR_HWI_E004+1)
+#define SKERR_HWI_E005MSG      "SkGeInitPort(): cannot init running ports"
+#define SKERR_HWI_E006         (SKERR_HWI_E005+1)
+#define SKERR_HWI_E006MSG      "SkGeMacInit(): PState does not match HW state"
+#define SKERR_HWI_E007         (SKERR_HWI_E006+1)
+#define SKERR_HWI_E007MSG      "SkXmInitDupMd() called with invalid Dup Mode"
+#define SKERR_HWI_E008         (SKERR_HWI_E007+1)
+#define SKERR_HWI_E008MSG      "SkXmSetRxCmd() called with invalid Mode"
+#define SKERR_HWI_E009         (SKERR_HWI_E008+1)
+#define SKERR_HWI_E009MSG      "SkGeCfgSync() called although PXSQSize zero"
+#define SKERR_HWI_E010         (SKERR_HWI_E009+1)
+#define SKERR_HWI_E010MSG      "SkGeCfgSync() called with invalid parameters"
+#define SKERR_HWI_E011         (SKERR_HWI_E010+1)
+#define SKERR_HWI_E011MSG      "SkGeInitPort(): Receive Queue Size too small"
+#define SKERR_HWI_E012         (SKERR_HWI_E011+1)
+#define SKERR_HWI_E012MSG      "SkGeInitPort(): invalid Queue Size specified"
+#define SKERR_HWI_E013         (SKERR_HWI_E012+1)
+#define SKERR_HWI_E013MSG      "SkGeInitPort(): cfg changed for running queue"
+#define SKERR_HWI_E014         (SKERR_HWI_E013+1)
+#define SKERR_HWI_E014MSG      "SkGeInitPort(): unknown GIPortUsage specified"
+#define SKERR_HWI_E015         (SKERR_HWI_E014+1)
+#define SKERR_HWI_E015MSG      "Illegal Link mode parameter"
+#define SKERR_HWI_E016         (SKERR_HWI_E015+1)
+#define SKERR_HWI_E016MSG      "Illegal Flow control mode parameter"
+#define SKERR_HWI_E017         (SKERR_HWI_E016+1)
+#define SKERR_HWI_E017MSG      "Illegal value specified for GIPollTimerVal"
+#define SKERR_HWI_E018         (SKERR_HWI_E017+1)
+#define SKERR_HWI_E018MSG      "FATAL: SkGeStopPort() does not terminate (Tx)"
+#define SKERR_HWI_E019         (SKERR_HWI_E018+1)
+#define SKERR_HWI_E019MSG      "Illegal Speed parameter"
+#define SKERR_HWI_E020         (SKERR_HWI_E019+1)
+#define SKERR_HWI_E020MSG      "Illegal Master/Slave parameter"
+#define SKERR_HWI_E021         (SKERR_HWI_E020+1)
+#define        SKERR_HWI_E021MSG       "MacUpdateStats(): cannot update statistic counter"
+#define        SKERR_HWI_E022          (SKERR_HWI_E021+1)
+#define        SKERR_HWI_E022MSG       "MacStatistic(): illegal statistic base address"
+#define SKERR_HWI_E023         (SKERR_HWI_E022+1)
+#define SKERR_HWI_E023MSG      "SkGeInitPort(): Transmit Queue Size too small"
+#define SKERR_HWI_E024         (SKERR_HWI_E023+1)
+#define SKERR_HWI_E024MSG      "FATAL: SkGeStopPort() does not terminate (Rx)"
+#define SKERR_HWI_E025         (SKERR_HWI_E024+1)
+#define SKERR_HWI_E025MSG      ""
+
+/* function prototypes ********************************************************/
+
+#ifndef        SK_KR_PROTO
+
+/*
+ * public functions in skgeinit.c
+ */
+extern void    SkGePollTxD(
+       SK_AC   *pAC,
+       SK_IOC  IoC,
+       int             Port,
+       SK_BOOL PollTxD);
+
+extern void    SkGeYellowLED(
+       SK_AC   *pAC,
+       SK_IOC  IoC,
+       int             State);
+
+extern int     SkGeCfgSync(
+       SK_AC   *pAC,
+       SK_IOC  IoC,
+       int             Port,
+       SK_U32  IntTime,
+       SK_U32  LimCount,
+       int             SyncMode);
+
+extern void    SkGeLoadLnkSyncCnt(
+       SK_AC   *pAC,
+       SK_IOC  IoC,
+       int             Port,
+       SK_U32  CntVal);
+
+extern void    SkGeStopPort(
+       SK_AC   *pAC,
+       SK_IOC  IoC,
+       int             Port,
+       int             Dir,
+       int             RstMode);
+
+extern int     SkGeInit(
+       SK_AC   *pAC,
+       SK_IOC  IoC,
+       int             Level);
+
+extern void    SkGeDeInit(
+       SK_AC   *pAC,
+       SK_IOC  IoC);
+
+extern int     SkGeInitPort(
+       SK_AC   *pAC,
+       SK_IOC  IoC,
+       int             Port);
+
+extern void    SkGeXmitLED(
+       SK_AC   *pAC,
+       SK_IOC  IoC,
+       int             Led,
+       int             Mode);
+
+extern int     SkGeInitAssignRamToQueues(
+       SK_AC   *pAC,
+       int             ActivePort,
+       SK_BOOL DualNet);
+
+/*
+ * public functions in skxmac2.c
+ */
+extern void SkMacRxTxDisable(
+       SK_AC   *pAC,
+       SK_IOC  IoC,
+       int             Port);
+
+extern void    SkMacSoftRst(
+       SK_AC   *pAC,
+       SK_IOC  IoC,
+       int             Port);
+
+extern void    SkMacHardRst(
+       SK_AC   *pAC,
+       SK_IOC  IoC,
+       int             Port);
+
+extern void    SkXmInitMac(
+       SK_AC   *pAC,
+       SK_IOC  IoC,
+       int             Port);
+
+extern void    SkGmInitMac(
+       SK_AC   *pAC,
+       SK_IOC  IoC,
+       int             Port);
+
+extern void SkMacInitPhy(
+       SK_AC   *pAC,
+       SK_IOC  IoC,
+       int             Port,
+       SK_BOOL DoLoop);
+
+extern void SkMacIrqDisable(
+       SK_AC   *pAC,
+       SK_IOC  IoC,
+       int             Port);
+
+extern void    SkMacFlushTxFifo(
+       SK_AC   *pAC,
+       SK_IOC  IoC,
+       int             Port);
+
+extern void    SkMacIrq(
+       SK_AC   *pAC,
+       SK_IOC  IoC,
+       int             Port);
+
+extern int     SkMacAutoNegDone(
+       SK_AC   *pAC,
+       SK_IOC  IoC,
+       int             Port);
+
+extern void    SkMacAutoNegLipaPhy(
+       SK_AC   *pAC,
+       SK_IOC  IoC,
+       int             Port,
+       SK_U16  IStatus);
+
+extern int  SkMacRxTxEnable(
+       SK_AC   *pAC,
+       SK_IOC  IoC,
+       int             Port);
+
+extern void    SkMacPromiscMode(
+       SK_AC   *pAC,
+       SK_IOC  IoC,
+       int             Port,
+       SK_BOOL Enable);
+
+extern void    SkMacHashing(
+       SK_AC   *pAC,
+       SK_IOC  IoC,
+       int             Port,
+       SK_BOOL Enable);
+
+extern void    SkXmPhyRead(
+       SK_AC   *pAC,
+       SK_IOC  IoC,
+       int             Port,
+       int             Addr,
+       SK_U16  SK_FAR *pVal);
+
+extern void    SkXmPhyWrite(
+       SK_AC   *pAC,
+       SK_IOC  IoC,
+       int             Port,
+       int             Addr,
+       SK_U16  Val);
+
+extern void    SkGmPhyRead(
+       SK_AC   *pAC,
+       SK_IOC  IoC,
+       int             Port,
+       int             Addr,
+       SK_U16  SK_FAR *pVal);
+
+extern void    SkGmPhyWrite(
+       SK_AC   *pAC,
+       SK_IOC  IoC,
+       int             Port,
+       int             Addr,
+       SK_U16  Val);
+
+extern void    SkXmClrExactAddr(
+       SK_AC   *pAC,
+       SK_IOC  IoC,
+       int             Port,
+       int             StartNum,
+       int             StopNum);
+
+extern void    SkXmAutoNegLipaXmac(
+       SK_AC   *pAC,
+       SK_IOC  IoC,
+       int             Port,
+       SK_U16  IStatus);
+
+extern int SkXmUpdateStats(
+       SK_AC   *pAC,
+       SK_IOC  IoC,
+       unsigned int Port);
+
+extern int SkGmUpdateStats(
+       SK_AC   *pAC,
+       SK_IOC  IoC,
+       unsigned int Port);
+
+extern int SkXmMacStatistic(
+       SK_AC   *pAC,
+       SK_IOC  IoC,
+       unsigned int Port,
+       SK_U16  StatAddr,
+       SK_U32  SK_FAR *pVal);
+
+extern int SkGmMacStatistic(
+       SK_AC   *pAC,
+       SK_IOC  IoC,
+       unsigned int Port,
+       SK_U16  StatAddr,
+       SK_U32  SK_FAR *pVal);
+
+extern int SkXmResetCounter(
+       SK_AC   *pAC,
+       SK_IOC  IoC,
+       unsigned int Port);
+
+extern int SkGmResetCounter(
+       SK_AC   *pAC,
+       SK_IOC  IoC,
+       unsigned int Port);
+
+extern int SkXmOverflowStatus(
+       SK_AC   *pAC,
+       SK_IOC  IoC,
+       unsigned int Port,
+       SK_U16  IStatus,
+       SK_U64  SK_FAR *pStatus);
+
+extern int SkGmOverflowStatus(
+       SK_AC   *pAC,
+       SK_IOC  IoC,
+       unsigned int Port,
+       SK_U16  MacStatus,
+       SK_U64  SK_FAR *pStatus);
+
+extern int SkGmCableDiagStatus(
+       SK_AC   *pAC,
+       SK_IOC  IoC,
+       int             Port,
+       SK_BOOL StartTest);
+
+#ifdef SK_DIAG
+extern void    SkGePhyRead(
+       SK_AC   *pAC,
+       SK_IOC  IoC,
+       int             Port,
+       int             Addr,
+       SK_U16  *pVal);
+
+extern void    SkGePhyWrite(
+       SK_AC   *pAC,
+       SK_IOC  IoC,
+       int             Port,
+       int             Addr,
+       SK_U16  Val);
+
+extern void    SkMacSetRxCmd(
+       SK_AC   *pAC,
+       SK_IOC  IoC,
+       int             Port,
+       int             Mode);
+extern void    SkMacCrcGener(
+       SK_AC   *pAC,
+       SK_IOC  IoC,
+       int             Port,
+       SK_BOOL Enable);
+extern void    SkMacTimeStamp(
+       SK_AC   *pAC,
+       SK_IOC  IoC,
+       int             Port,
+       SK_BOOL Enable);
+extern void    SkXmSendCont(
+       SK_AC   *pAC,
+       SK_IOC  IoC,
+       int             Port,
+       SK_BOOL Enable);
+#endif /* SK_DIAG */
+
+#else  /* SK_KR_PROTO */
+
+/*
+ * public functions in skgeinit.c
+ */
+extern void    SkGePollTxD();
+extern void    SkGeYellowLED();
+extern int     SkGeCfgSync();
+extern void    SkGeLoadLnkSyncCnt();
+extern void    SkGeStopPort();
+extern int     SkGeInit();
+extern void    SkGeDeInit();
+extern int     SkGeInitPort();
+extern void    SkGeXmitLED();
+extern int     SkGeInitAssignRamToQueues();
+
+/*
+ * public functions in skxmac2.c
+ */
+extern void SkMacRxTxDisable();
+extern void    SkMacSoftRst();
+extern void    SkMacHardRst();
+extern void SkMacInitPhy();
+extern int  SkMacRxTxEnable();
+extern void SkMacPromiscMode();
+extern void SkMacHashing();
+extern void SkMacIrqDisable();
+extern void    SkMacFlushTxFifo();
+extern void    SkMacIrq();
+extern int     SkMacAutoNegDone();
+extern void    SkMacAutoNegLipaPhy();
+extern void    SkXmInitMac();
+extern void    SkXmPhyRead();
+extern void    SkXmPhyWrite();
+extern void    SkGmInitMac();
+extern void    SkGmPhyRead();
+extern void    SkGmPhyWrite();
+extern void    SkXmClrExactAddr();
+extern void    SkXmAutoNegLipaXmac();
+extern int     SkXmUpdateStats();
+extern int     SkGmUpdateStats();
+extern int     SkXmMacStatistic();
+extern int     SkGmMacStatistic();
+extern int     SkXmResetCounter();
+extern int     SkGmResetCounter();
+extern int     SkXmOverflowStatus();
+extern int     SkGmOverflowStatus();
+extern int     SkGmCableDiagStatus();
+
+#ifdef SK_DIAG
+extern void    SkGePhyRead();
+extern void    SkGePhyWrite();
+extern void    SkMacSetRxCmd();
+extern void    SkMacCrcGener();
+extern void    SkMacTimeStamp();
+extern void    SkXmSendCont();
+#endif /* SK_DIAG */
+
+#endif /* SK_KR_PROTO */
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __INC_SKGEINIT_H_ */
diff --git a/drivers/net/sk98lin/h/skgepnm2.h b/drivers/net/sk98lin/h/skgepnm2.h
new file mode 100644 (file)
index 0000000..ddd304f
--- /dev/null
@@ -0,0 +1,334 @@
+/*****************************************************************************
+ *
+ * Name:       skgepnm2.h
+ * Project:    GEnesis, PCI Gigabit Ethernet Adapter
+ * Version:    $Revision: 1.36 $
+ * Date:       $Date: 2003/05/23 12:45:13 $
+ * Purpose:    Defines for Private Network Management Interface
+ *
+ ****************************************************************************/
+
+/******************************************************************************
+ *
+ *     (C)Copyright 1998-2002 SysKonnect GmbH.
+ *     (C)Copyright 2002-2003 Marvell.
+ *
+ *     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.
+ *
+ *     The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+#ifndef _SKGEPNM2_H_
+#define _SKGEPNM2_H_
+
+/*
+ * General definitions
+ */
+#define SK_PNMI_CHIPSET_XMAC   1       /* XMAC11800FP */
+#define SK_PNMI_CHIPSET_YUKON  2       /* YUKON */
+
+#define        SK_PNMI_BUS_PCI         1       /* PCI bus*/
+
+/*
+ * Actions
+ */
+#define SK_PNMI_ACT_IDLE               1
+#define SK_PNMI_ACT_RESET              2
+#define SK_PNMI_ACT_SELFTEST   3
+#define SK_PNMI_ACT_RESETCNT   4
+
+/*
+ * VPD releated defines
+ */
+
+#define SK_PNMI_VPD_RW         1
+#define SK_PNMI_VPD_RO         2
+
+#define SK_PNMI_VPD_OK                 0
+#define SK_PNMI_VPD_NOTFOUND   1
+#define SK_PNMI_VPD_CUT                        2
+#define SK_PNMI_VPD_TIMEOUT            3
+#define SK_PNMI_VPD_FULL               4
+#define SK_PNMI_VPD_NOWRITE            5
+#define SK_PNMI_VPD_FATAL              6
+
+#define SK_PNMI_VPD_IGNORE     0
+#define SK_PNMI_VPD_CREATE     1
+#define SK_PNMI_VPD_DELETE     2
+
+
+/*
+ * RLMT related defines
+ */
+#define SK_PNMI_DEF_RLMT_CHG_THRES     240     /* 4 changes per minute */
+
+
+/*
+ * VCT internal status values
+ */
+#define SK_PNMI_VCT_PENDING    32
+#define SK_PNMI_VCT_TEST_DONE  64
+#define SK_PNMI_VCT_LINK       128
+
+/*
+ * Internal table definitions
+ */
+#define SK_PNMI_GET            0
+#define SK_PNMI_PRESET 1
+#define SK_PNMI_SET            2
+
+#define SK_PNMI_RO             0
+#define SK_PNMI_RW             1
+#define SK_PNMI_WO             2
+
+typedef struct s_OidTabEntry {
+       SK_U32                  Id;
+       SK_U32                  InstanceNo;
+       unsigned int    StructSize;
+       unsigned int    Offset;
+       int                             Access;
+       int                             (* Func)(SK_AC *pAc, SK_IOC pIo, int action,
+                                                        SK_U32 Id, char* pBuf, unsigned int* pLen,
+                                                        SK_U32 Instance, unsigned int TableIndex,
+                                                        SK_U32 NetNumber);
+       SK_U16                  Param;
+} SK_PNMI_TAB_ENTRY;
+
+
+/*
+ * Trap lengths
+ */
+#define SK_PNMI_TRAP_SIMPLE_LEN                        17
+#define SK_PNMI_TRAP_SENSOR_LEN_BASE   46
+#define SK_PNMI_TRAP_RLMT_CHANGE_LEN   23
+#define SK_PNMI_TRAP_RLMT_PORT_LEN             23
+
+/*
+ * Number of MAC types supported
+ */
+#define SK_PNMI_MAC_TYPES      (SK_MAC_GMAC + 1)
+
+/*
+ * MAC statistic data list (overall set for MAC types used)
+ */
+enum SK_MACSTATS {
+       SK_PNMI_HTX                             = 0,
+       SK_PNMI_HTX_OCTET,
+       SK_PNMI_HTX_OCTETHIGH   = SK_PNMI_HTX_OCTET,
+       SK_PNMI_HTX_OCTETLOW,
+       SK_PNMI_HTX_BROADCAST,
+       SK_PNMI_HTX_MULTICAST,
+       SK_PNMI_HTX_UNICAST,
+       SK_PNMI_HTX_BURST,
+       SK_PNMI_HTX_PMACC,
+       SK_PNMI_HTX_MACC,
+       SK_PNMI_HTX_COL,
+       SK_PNMI_HTX_SINGLE_COL,
+       SK_PNMI_HTX_MULTI_COL,
+       SK_PNMI_HTX_EXCESS_COL,
+       SK_PNMI_HTX_LATE_COL,
+       SK_PNMI_HTX_DEFFERAL,
+       SK_PNMI_HTX_EXCESS_DEF,
+       SK_PNMI_HTX_UNDERRUN,
+       SK_PNMI_HTX_CARRIER,
+       SK_PNMI_HTX_UTILUNDER,
+       SK_PNMI_HTX_UTILOVER,
+       SK_PNMI_HTX_64,
+       SK_PNMI_HTX_127,
+       SK_PNMI_HTX_255,
+       SK_PNMI_HTX_511,
+       SK_PNMI_HTX_1023,
+       SK_PNMI_HTX_MAX,
+       SK_PNMI_HTX_LONGFRAMES,
+       SK_PNMI_HTX_SYNC,
+       SK_PNMI_HTX_SYNC_OCTET,
+       SK_PNMI_HTX_RESERVED,
+       
+       SK_PNMI_HRX,
+       SK_PNMI_HRX_OCTET,
+       SK_PNMI_HRX_OCTETHIGH   = SK_PNMI_HRX_OCTET,
+       SK_PNMI_HRX_OCTETLOW,
+       SK_PNMI_HRX_BADOCTET,
+       SK_PNMI_HRX_BADOCTETHIGH = SK_PNMI_HRX_BADOCTET,
+       SK_PNMI_HRX_BADOCTETLOW,
+       SK_PNMI_HRX_BROADCAST,
+       SK_PNMI_HRX_MULTICAST,
+       SK_PNMI_HRX_UNICAST,
+       SK_PNMI_HRX_PMACC,
+       SK_PNMI_HRX_MACC,
+       SK_PNMI_HRX_PMACC_ERR,
+       SK_PNMI_HRX_MACC_UNKWN,
+       SK_PNMI_HRX_BURST,
+       SK_PNMI_HRX_MISSED,
+       SK_PNMI_HRX_FRAMING,
+       SK_PNMI_HRX_UNDERSIZE,
+       SK_PNMI_HRX_OVERFLOW,
+       SK_PNMI_HRX_JABBER,
+       SK_PNMI_HRX_CARRIER,
+       SK_PNMI_HRX_IRLENGTH,
+       SK_PNMI_HRX_SYMBOL,
+       SK_PNMI_HRX_SHORTS,
+       SK_PNMI_HRX_RUNT,
+       SK_PNMI_HRX_TOO_LONG,
+       SK_PNMI_HRX_FCS,
+       SK_PNMI_HRX_CEXT,
+       SK_PNMI_HRX_UTILUNDER,
+       SK_PNMI_HRX_UTILOVER,
+       SK_PNMI_HRX_64,
+       SK_PNMI_HRX_127,
+       SK_PNMI_HRX_255,
+       SK_PNMI_HRX_511,
+       SK_PNMI_HRX_1023,
+       SK_PNMI_HRX_MAX,
+       SK_PNMI_HRX_LONGFRAMES,
+       
+       SK_PNMI_HRX_RESERVED,
+       
+       SK_PNMI_MAX_IDX         /* NOTE: Ensure SK_PNMI_CNT_NO is set to this value */
+};
+
+/*
+ * MAC specific data
+ */
+typedef struct s_PnmiStatAddr {
+       SK_U16          Reg;            /* MAC register containing the value */
+       SK_BOOL         GetOffset;      /* TRUE: Offset managed by PNMI (call GetStatVal())*/
+} SK_PNMI_STATADDR;
+
+
+/*
+ * SK_PNMI_STRUCT_DATA copy offset evaluation macros
+ */
+#define SK_PNMI_OFF(e)         ((SK_U32)(SK_UPTR)&(((SK_PNMI_STRUCT_DATA *)0)->e))
+#define SK_PNMI_MAI_OFF(e)     ((SK_U32)(SK_UPTR)&(((SK_PNMI_STRUCT_DATA *)0)->e))
+#define SK_PNMI_VPD_OFF(e)     ((SK_U32)(SK_UPTR)&(((SK_PNMI_VPD *)0)->e))
+#define SK_PNMI_SEN_OFF(e)     ((SK_U32)(SK_UPTR)&(((SK_PNMI_SENSOR *)0)->e))
+#define SK_PNMI_CHK_OFF(e)     ((SK_U32)(SK_UPTR)&(((SK_PNMI_CHECKSUM *)0)->e))
+#define SK_PNMI_STA_OFF(e)     ((SK_U32)(SK_UPTR)&(((SK_PNMI_STAT *)0)->e))
+#define SK_PNMI_CNF_OFF(e)     ((SK_U32)(SK_UPTR)&(((SK_PNMI_CONF *)0)->e))
+#define SK_PNMI_RLM_OFF(e)     ((SK_U32)(SK_UPTR)&(((SK_PNMI_RLMT *)0)->e))
+#define SK_PNMI_MON_OFF(e)     ((SK_U32)(SK_UPTR)&(((SK_PNMI_RLMT_MONITOR *)0)->e))
+#define SK_PNMI_TRP_OFF(e)     ((SK_U32)(SK_UPTR)&(((SK_PNMI_TRAP *)0)->e))
+
+#define SK_PNMI_SET_STAT(b,s,o)        {SK_U32 Val32; char *pVal; \
+                                       Val32 = (s); \
+                                       pVal = (char *)(b) + ((SK_U32)(SK_UPTR) \
+                                               &(((SK_PNMI_STRUCT_DATA *)0)-> \
+                                               ReturnStatus.ErrorStatus)); \
+                                       SK_PNMI_STORE_U32(pVal, Val32); \
+                                       Val32 = (o); \
+                                       pVal = (char *)(b) + ((SK_U32)(SK_UPTR) \
+                                               &(((SK_PNMI_STRUCT_DATA *)0)-> \
+                                               ReturnStatus.ErrorOffset)); \
+                                       SK_PNMI_STORE_U32(pVal, Val32);}
+
+/*
+ * Time macros
+ */
+#ifndef SK_PNMI_HUNDREDS_SEC
+#if SK_TICKS_PER_SEC == 100
+#define SK_PNMI_HUNDREDS_SEC(t)        (t)
+#else
+#define SK_PNMI_HUNDREDS_SEC(t)        (((t) * 100) / (SK_TICKS_PER_SEC))
+#endif /* !SK_TICKS_PER_SEC */
+#endif /* !SK_PNMI_HUNDREDS_SEC */
+
+/*
+ * Macros to work around alignment problems
+ */
+#ifndef SK_PNMI_STORE_U16
+#define SK_PNMI_STORE_U16(p,v) {*(char *)(p) = *((char *)&(v)); \
+                                       *((char *)(p) + 1) = \
+                                               *(((char *)&(v)) + 1);}
+#endif
+
+#ifndef SK_PNMI_STORE_U32
+#define SK_PNMI_STORE_U32(p,v) {*(char *)(p) = *((char *)&(v)); \
+                                       *((char *)(p) + 1) = \
+                                               *(((char *)&(v)) + 1); \
+                                       *((char *)(p) + 2) = \
+                                               *(((char *)&(v)) + 2); \
+                                       *((char *)(p) + 3) = \
+                                               *(((char *)&(v)) + 3);}
+#endif
+
+#ifndef SK_PNMI_STORE_U64
+#define SK_PNMI_STORE_U64(p,v) {*(char *)(p) = *((char *)&(v)); \
+                                       *((char *)(p) + 1) = \
+                                               *(((char *)&(v)) + 1); \
+                                       *((char *)(p) + 2) = \
+                                               *(((char *)&(v)) + 2); \
+                                       *((char *)(p) + 3) = \
+                                               *(((char *)&(v)) + 3); \
+                                       *((char *)(p) + 4) = \
+                                               *(((char *)&(v)) + 4); \
+                                       *((char *)(p) + 5) = \
+                                               *(((char *)&(v)) + 5); \
+                                       *((char *)(p) + 6) = \
+                                               *(((char *)&(v)) + 6); \
+                                       *((char *)(p) + 7) = \
+                                               *(((char *)&(v)) + 7);}
+#endif
+
+#ifndef SK_PNMI_READ_U16
+#define SK_PNMI_READ_U16(p,v)  {*((char *)&(v)) = *(char *)(p); \
+                                       *(((char *)&(v)) + 1) = \
+                                               *((char *)(p) + 1);}
+#endif
+
+#ifndef SK_PNMI_READ_U32
+#define SK_PNMI_READ_U32(p,v)  {*((char *)&(v)) = *(char *)(p); \
+                                       *(((char *)&(v)) + 1) = \
+                                               *((char *)(p) + 1); \
+                                       *(((char *)&(v)) + 2) = \
+                                               *((char *)(p) + 2); \
+                                       *(((char *)&(v)) + 3) = \
+                                               *((char *)(p) + 3);}
+#endif
+
+#ifndef SK_PNMI_READ_U64
+#define SK_PNMI_READ_U64(p,v)  {*((char *)&(v)) = *(char *)(p); \
+                                       *(((char *)&(v)) + 1) = \
+                                               *((char *)(p) + 1); \
+                                       *(((char *)&(v)) + 2) = \
+                                               *((char *)(p) + 2); \
+                                       *(((char *)&(v)) + 3) = \
+                                               *((char *)(p) + 3); \
+                                       *(((char *)&(v)) + 4) = \
+                                               *((char *)(p) + 4); \
+                                       *(((char *)&(v)) + 5) = \
+                                               *((char *)(p) + 5); \
+                                       *(((char *)&(v)) + 6) = \
+                                               *((char *)(p) + 6); \
+                                       *(((char *)&(v)) + 7) = \
+                                               *((char *)(p) + 7);}
+#endif
+
+/*
+ * Macros for Debug
+ */
+#ifdef DEBUG
+
+#define SK_PNMI_CHECKFLAGS(vSt)        {if (pAC->Pnmi.MacUpdatedFlag > 0 || \
+                                       pAC->Pnmi.RlmtUpdatedFlag > 0 || \
+                                       pAC->Pnmi.SirqUpdatedFlag > 0) { \
+                                               SK_DBG_MSG(pAC, \
+                                               SK_DBGMOD_PNMI, \
+                                               SK_DBGCAT_CTRL, \
+                                               ("PNMI: ERR: %s MacUFlag=%d, RlmtUFlag=%d, SirqUFlag=%d\n", \
+                                               vSt, \
+                                               pAC->Pnmi.MacUpdatedFlag, \
+                                               pAC->Pnmi.RlmtUpdatedFlag, \
+                                               pAC->Pnmi.SirqUpdatedFlag))}}
+
+#else  /* !DEBUG */
+
+#define SK_PNMI_CHECKFLAGS(vSt)        /* Nothing */
+
+#endif /* !DEBUG */
+
+#endif /* _SKGEPNM2_H_ */
diff --git a/drivers/net/sk98lin/h/skgepnmi.h b/drivers/net/sk98lin/h/skgepnmi.h
new file mode 100644 (file)
index 0000000..1ed214c
--- /dev/null
@@ -0,0 +1,962 @@
+/*****************************************************************************
+ *
+ * Name:       skgepnmi.h
+ * Project:    GEnesis, PCI Gigabit Ethernet Adapter
+ * Version:    $Revision: 1.62 $
+ * Date:       $Date: 2003/08/15 12:31:52 $
+ * Purpose:    Defines for Private Network Management Interface
+ *
+ ****************************************************************************/
+
+/******************************************************************************
+ *
+ *     (C)Copyright 1998-2002 SysKonnect GmbH.
+ *     (C)Copyright 2002-2003 Marvell.
+ *
+ *     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.
+ *
+ *     The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+#ifndef _SKGEPNMI_H_
+#define _SKGEPNMI_H_
+
+/*
+ * Include dependencies
+ */
+#include "h/sktypes.h"
+#include "h/skerror.h"
+#include "h/sktimer.h"
+#include "h/ski2c.h"
+#include "h/skaddr.h"
+#include "h/skrlmt.h"
+#include "h/skvpd.h"
+
+/*
+ * Management Database Version
+ */
+#define SK_PNMI_MDB_VERSION            0x00030001      /* 3.1 */
+
+
+/*
+ * Event definitions
+ */
+#define SK_PNMI_EVT_SIRQ_OVERFLOW              1       /* Counter overflow */
+#define SK_PNMI_EVT_SEN_WAR_LOW                        2       /* Lower war thres exceeded */
+#define SK_PNMI_EVT_SEN_WAR_UPP                        3       /* Upper war thres exceeded */
+#define SK_PNMI_EVT_SEN_ERR_LOW                        4       /* Lower err thres exceeded */
+#define SK_PNMI_EVT_SEN_ERR_UPP                        5       /* Upper err thres exceeded */
+#define SK_PNMI_EVT_CHG_EST_TIMER              6       /* Timer event for RLMT Chg */
+#define SK_PNMI_EVT_UTILIZATION_TIMER  7       /* Timer event for Utiliza. */
+#define SK_PNMI_EVT_CLEAR_COUNTER              8       /* Clear statistic counters */
+#define SK_PNMI_EVT_XMAC_RESET                 9       /* XMAC will be reset */
+
+#define SK_PNMI_EVT_RLMT_PORT_UP               10      /* Port came logically up */
+#define SK_PNMI_EVT_RLMT_PORT_DOWN             11      /* Port went logically down */
+#define SK_PNMI_EVT_RLMT_SEGMENTATION  13      /* Two SP root bridges found */
+#define SK_PNMI_EVT_RLMT_ACTIVE_DOWN   14      /* Port went logically down */
+#define SK_PNMI_EVT_RLMT_ACTIVE_UP             15      /* Port came logically up */
+#define SK_PNMI_EVT_RLMT_SET_NETS              16      /* 1. Parameter is number of nets
+                                                                                               1 = single net; 2 = dual net */
+#define SK_PNMI_EVT_VCT_RESET          17      /* VCT port reset timer event started with SET. */
+
+
+/*
+ * Return values
+ */
+#define SK_PNMI_ERR_OK                         0
+#define SK_PNMI_ERR_GENERAL                    1
+#define SK_PNMI_ERR_TOO_SHORT          2
+#define SK_PNMI_ERR_BAD_VALUE          3
+#define SK_PNMI_ERR_READ_ONLY          4
+#define SK_PNMI_ERR_UNKNOWN_OID                5
+#define SK_PNMI_ERR_UNKNOWN_INST       6
+#define SK_PNMI_ERR_UNKNOWN_NET        7
+#define SK_PNMI_ERR_NOT_SUPPORTED      10
+
+
+/*
+ * Return values of driver reset function SK_DRIVER_RESET() and
+ * driver event function SK_DRIVER_EVENT()
+ */
+#define SK_PNMI_ERR_OK                 0
+#define SK_PNMI_ERR_FAIL               1
+
+
+/*
+ * Return values of driver test function SK_DRIVER_SELFTEST()
+ */
+#define SK_PNMI_TST_UNKNOWN            (1 << 0)
+#define SK_PNMI_TST_TRANCEIVER         (1 << 1)
+#define SK_PNMI_TST_ASIC               (1 << 2)
+#define SK_PNMI_TST_SENSOR             (1 << 3)
+#define SK_PNMI_TST_POWERMGMT          (1 << 4)
+#define SK_PNMI_TST_PCI                        (1 << 5)
+#define SK_PNMI_TST_MAC                        (1 << 6)
+
+
+/*
+ * RLMT specific definitions
+ */
+#define SK_PNMI_RLMT_STATUS_STANDBY    1
+#define SK_PNMI_RLMT_STATUS_ACTIVE     2
+#define SK_PNMI_RLMT_STATUS_ERROR      3
+
+#define SK_PNMI_RLMT_LSTAT_PHY_DOWN    1
+#define SK_PNMI_RLMT_LSTAT_AUTONEG     2
+#define SK_PNMI_RLMT_LSTAT_LOG_DOWN    3
+#define SK_PNMI_RLMT_LSTAT_LOG_UP      4
+#define SK_PNMI_RLMT_LSTAT_INDETERMINATED 5
+
+#define SK_PNMI_RLMT_MODE_CHK_LINK     (SK_RLMT_CHECK_LINK)
+#define SK_PNMI_RLMT_MODE_CHK_RX       (SK_RLMT_CHECK_LOC_LINK)
+#define SK_PNMI_RLMT_MODE_CHK_SPT      (SK_RLMT_CHECK_SEG)
+/* #define SK_PNMI_RLMT_MODE_CHK_EX */
+
+/*
+ * OID definition
+ */
+#ifndef _NDIS_ /* Check, whether NDIS already included OIDs */
+
+#define OID_GEN_XMIT_OK                                        0x00020101
+#define OID_GEN_RCV_OK                                 0x00020102
+#define OID_GEN_XMIT_ERROR                             0x00020103
+#define OID_GEN_RCV_ERROR                              0x00020104
+#define OID_GEN_RCV_NO_BUFFER                  0x00020105
+
+/* #define OID_GEN_DIRECTED_BYTES_XMIT 0x00020201 */
+#define OID_GEN_DIRECTED_FRAMES_XMIT   0x00020202
+/* #define OID_GEN_MULTICAST_BYTES_XMIT        0x00020203 */
+#define OID_GEN_MULTICAST_FRAMES_XMIT  0x00020204
+/* #define OID_GEN_BROADCAST_BYTES_XMIT        0x00020205 */
+#define OID_GEN_BROADCAST_FRAMES_XMIT  0x00020206
+/* #define OID_GEN_DIRECTED_BYTES_RCV  0x00020207 */
+#define OID_GEN_DIRECTED_FRAMES_RCV            0x00020208
+/* #define OID_GEN_MULTICAST_BYTES_RCV 0x00020209 */
+#define OID_GEN_MULTICAST_FRAMES_RCV   0x0002020A
+/* #define OID_GEN_BROADCAST_BYTES_RCV 0x0002020B */
+#define OID_GEN_BROADCAST_FRAMES_RCV   0x0002020C
+#define OID_GEN_RCV_CRC_ERROR                  0x0002020D
+#define OID_GEN_TRANSMIT_QUEUE_LENGTH  0x0002020E
+
+#define OID_802_3_PERMANENT_ADDRESS            0x01010101
+#define OID_802_3_CURRENT_ADDRESS              0x01010102
+/* #define OID_802_3_MULTICAST_LIST            0x01010103 */
+/* #define OID_802_3_MAXIMUM_LIST_SIZE 0x01010104 */
+/* #define OID_802_3_MAC_OPTIONS               0x01010105 */
+                       
+#define OID_802_3_RCV_ERROR_ALIGNMENT  0x01020101
+#define OID_802_3_XMIT_ONE_COLLISION   0x01020102
+#define OID_802_3_XMIT_MORE_COLLISIONS 0x01020103
+#define OID_802_3_XMIT_DEFERRED                        0x01020201
+#define OID_802_3_XMIT_MAX_COLLISIONS  0x01020202
+#define OID_802_3_RCV_OVERRUN                  0x01020203
+#define OID_802_3_XMIT_UNDERRUN                        0x01020204
+#define OID_802_3_XMIT_TIMES_CRS_LOST  0x01020206
+#define OID_802_3_XMIT_LATE_COLLISIONS 0x01020207
+
+/*
+ * PnP and PM OIDs
+ */
+#ifdef SK_POWER_MGMT
+#define OID_PNP_CAPABILITIES                   0xFD010100
+#define OID_PNP_SET_POWER                              0xFD010101
+#define OID_PNP_QUERY_POWER                            0xFD010102
+#define OID_PNP_ADD_WAKE_UP_PATTERN            0xFD010103
+#define OID_PNP_REMOVE_WAKE_UP_PATTERN 0xFD010104
+#define OID_PNP_ENABLE_WAKE_UP                 0xFD010106
+#endif /* SK_POWER_MGMT */
+
+#endif /* _NDIS_ */
+
+#define OID_SKGE_MDB_VERSION                   0xFF010100
+#define OID_SKGE_SUPPORTED_LIST                        0xFF010101
+#define OID_SKGE_VPD_FREE_BYTES                        0xFF010102
+#define OID_SKGE_VPD_ENTRIES_LIST              0xFF010103
+#define OID_SKGE_VPD_ENTRIES_NUMBER            0xFF010104
+#define OID_SKGE_VPD_KEY                               0xFF010105
+#define OID_SKGE_VPD_VALUE                             0xFF010106
+#define OID_SKGE_VPD_ACCESS                            0xFF010107
+#define OID_SKGE_VPD_ACTION                            0xFF010108
+                       
+#define OID_SKGE_PORT_NUMBER                   0xFF010110
+#define OID_SKGE_DEVICE_TYPE                   0xFF010111
+#define OID_SKGE_DRIVER_DESCR                  0xFF010112
+#define OID_SKGE_DRIVER_VERSION                        0xFF010113
+#define OID_SKGE_HW_DESCR                              0xFF010114
+#define OID_SKGE_HW_VERSION                            0xFF010115
+#define OID_SKGE_CHIPSET                               0xFF010116
+#define OID_SKGE_ACTION                                        0xFF010117
+#define OID_SKGE_RESULT                                        0xFF010118
+#define OID_SKGE_BUS_TYPE                              0xFF010119
+#define OID_SKGE_BUS_SPEED                             0xFF01011A
+#define OID_SKGE_BUS_WIDTH                             0xFF01011B
+/* 0xFF01011C unused */
+#define OID_SKGE_DIAG_ACTION                   0xFF01011D
+#define OID_SKGE_DIAG_RESULT                   0xFF01011E
+#define OID_SKGE_MTU                                   0xFF01011F
+#define OID_SKGE_PHYS_CUR_ADDR                 0xFF010120
+#define OID_SKGE_PHYS_FAC_ADDR                 0xFF010121
+#define OID_SKGE_PMD                                   0xFF010122
+#define OID_SKGE_CONNECTOR                             0xFF010123
+#define OID_SKGE_LINK_CAP                              0xFF010124
+#define OID_SKGE_LINK_MODE                             0xFF010125
+#define OID_SKGE_LINK_MODE_STATUS              0xFF010126
+#define OID_SKGE_LINK_STATUS                   0xFF010127
+#define OID_SKGE_FLOWCTRL_CAP                  0xFF010128
+#define OID_SKGE_FLOWCTRL_MODE                 0xFF010129
+#define OID_SKGE_FLOWCTRL_STATUS               0xFF01012A
+#define OID_SKGE_PHY_OPERATION_CAP             0xFF01012B
+#define OID_SKGE_PHY_OPERATION_MODE            0xFF01012C
+#define OID_SKGE_PHY_OPERATION_STATUS  0xFF01012D
+#define OID_SKGE_MULTICAST_LIST                        0xFF01012E
+#define OID_SKGE_CURRENT_PACKET_FILTER 0xFF01012F
+
+#define OID_SKGE_TRAP                                  0xFF010130
+#define OID_SKGE_TRAP_NUMBER                   0xFF010131
+
+#define OID_SKGE_RLMT_MODE                             0xFF010140
+#define OID_SKGE_RLMT_PORT_NUMBER              0xFF010141
+#define OID_SKGE_RLMT_PORT_ACTIVE              0xFF010142
+#define OID_SKGE_RLMT_PORT_PREFERRED   0xFF010143
+#define OID_SKGE_INTERMEDIATE_SUPPORT  0xFF010160
+
+#define OID_SKGE_SPEED_CAP                             0xFF010170
+#define OID_SKGE_SPEED_MODE                            0xFF010171
+#define OID_SKGE_SPEED_STATUS                  0xFF010172
+
+#define OID_SKGE_BOARDLEVEL                            0xFF010180
+
+#define OID_SKGE_SENSOR_NUMBER                 0xFF020100                      
+#define OID_SKGE_SENSOR_INDEX                  0xFF020101
+#define OID_SKGE_SENSOR_DESCR                  0xFF020102
+#define OID_SKGE_SENSOR_TYPE                   0xFF020103
+#define OID_SKGE_SENSOR_VALUE                  0xFF020104
+#define OID_SKGE_SENSOR_WAR_THRES_LOW  0xFF020105
+#define OID_SKGE_SENSOR_WAR_THRES_UPP  0xFF020106
+#define OID_SKGE_SENSOR_ERR_THRES_LOW  0xFF020107
+#define OID_SKGE_SENSOR_ERR_THRES_UPP  0xFF020108
+#define OID_SKGE_SENSOR_STATUS                 0xFF020109
+#define OID_SKGE_SENSOR_WAR_CTS                        0xFF02010A
+#define OID_SKGE_SENSOR_ERR_CTS                        0xFF02010B
+#define OID_SKGE_SENSOR_WAR_TIME               0xFF02010C
+#define OID_SKGE_SENSOR_ERR_TIME               0xFF02010D
+
+#define OID_SKGE_CHKSM_NUMBER                  0xFF020110
+#define OID_SKGE_CHKSM_RX_OK_CTS               0xFF020111
+#define OID_SKGE_CHKSM_RX_UNABLE_CTS   0xFF020112
+#define OID_SKGE_CHKSM_RX_ERR_CTS              0xFF020113
+#define OID_SKGE_CHKSM_TX_OK_CTS               0xFF020114
+#define OID_SKGE_CHKSM_TX_UNABLE_CTS   0xFF020115
+
+#define OID_SKGE_STAT_TX                               0xFF020120
+#define OID_SKGE_STAT_TX_OCTETS                        0xFF020121
+#define OID_SKGE_STAT_TX_BROADCAST             0xFF020122
+#define OID_SKGE_STAT_TX_MULTICAST             0xFF020123
+#define OID_SKGE_STAT_TX_UNICAST               0xFF020124
+#define OID_SKGE_STAT_TX_LONGFRAMES            0xFF020125
+#define OID_SKGE_STAT_TX_BURST                 0xFF020126
+#define OID_SKGE_STAT_TX_PFLOWC                        0xFF020127
+#define OID_SKGE_STAT_TX_FLOWC                 0xFF020128
+#define OID_SKGE_STAT_TX_SINGLE_COL            0xFF020129
+#define OID_SKGE_STAT_TX_MULTI_COL             0xFF02012A
+#define OID_SKGE_STAT_TX_EXCESS_COL            0xFF02012B
+#define OID_SKGE_STAT_TX_LATE_COL              0xFF02012C
+#define OID_SKGE_STAT_TX_DEFFERAL              0xFF02012D
+#define OID_SKGE_STAT_TX_EXCESS_DEF            0xFF02012E
+#define OID_SKGE_STAT_TX_UNDERRUN              0xFF02012F
+#define OID_SKGE_STAT_TX_CARRIER               0xFF020130
+/* #define OID_SKGE_STAT_TX_UTIL               0xFF020131 */
+#define OID_SKGE_STAT_TX_64                            0xFF020132
+#define OID_SKGE_STAT_TX_127                   0xFF020133
+#define OID_SKGE_STAT_TX_255                   0xFF020134
+#define OID_SKGE_STAT_TX_511                   0xFF020135
+#define OID_SKGE_STAT_TX_1023                  0xFF020136
+#define OID_SKGE_STAT_TX_MAX                   0xFF020137
+#define OID_SKGE_STAT_TX_SYNC                  0xFF020138
+#define OID_SKGE_STAT_TX_SYNC_OCTETS   0xFF020139
+#define OID_SKGE_STAT_RX                               0xFF02013A
+#define OID_SKGE_STAT_RX_OCTETS                        0xFF02013B
+#define OID_SKGE_STAT_RX_BROADCAST             0xFF02013C
+#define OID_SKGE_STAT_RX_MULTICAST             0xFF02013D
+#define OID_SKGE_STAT_RX_UNICAST               0xFF02013E
+#define OID_SKGE_STAT_RX_PFLOWC                        0xFF02013F
+#define OID_SKGE_STAT_RX_FLOWC                 0xFF020140
+#define OID_SKGE_STAT_RX_PFLOWC_ERR            0xFF020141
+#define OID_SKGE_STAT_RX_FLOWC_UNKWN   0xFF020142
+#define OID_SKGE_STAT_RX_BURST                 0xFF020143
+#define OID_SKGE_STAT_RX_MISSED                        0xFF020144
+#define OID_SKGE_STAT_RX_FRAMING               0xFF020145
+#define OID_SKGE_STAT_RX_OVERFLOW              0xFF020146
+#define OID_SKGE_STAT_RX_JABBER                        0xFF020147
+#define OID_SKGE_STAT_RX_CARRIER               0xFF020148
+#define OID_SKGE_STAT_RX_IR_LENGTH             0xFF020149
+#define OID_SKGE_STAT_RX_SYMBOL                        0xFF02014A
+#define OID_SKGE_STAT_RX_SHORTS                        0xFF02014B
+#define OID_SKGE_STAT_RX_RUNT                  0xFF02014C
+#define OID_SKGE_STAT_RX_CEXT                  0xFF02014D
+#define OID_SKGE_STAT_RX_TOO_LONG              0xFF02014E
+#define OID_SKGE_STAT_RX_FCS                   0xFF02014F
+/* #define OID_SKGE_STAT_RX_UTIL               0xFF020150 */
+#define OID_SKGE_STAT_RX_64                            0xFF020151
+#define OID_SKGE_STAT_RX_127                   0xFF020152
+#define OID_SKGE_STAT_RX_255                   0xFF020153
+#define OID_SKGE_STAT_RX_511                   0xFF020154
+#define OID_SKGE_STAT_RX_1023                  0xFF020155
+#define OID_SKGE_STAT_RX_MAX                   0xFF020156
+#define OID_SKGE_STAT_RX_LONGFRAMES            0xFF020157
+
+#define OID_SKGE_RLMT_CHANGE_CTS               0xFF020160
+#define OID_SKGE_RLMT_CHANGE_TIME              0xFF020161
+#define OID_SKGE_RLMT_CHANGE_ESTIM             0xFF020162
+#define OID_SKGE_RLMT_CHANGE_THRES             0xFF020163
+
+#define OID_SKGE_RLMT_PORT_INDEX               0xFF020164
+#define OID_SKGE_RLMT_STATUS                   0xFF020165
+#define OID_SKGE_RLMT_TX_HELLO_CTS             0xFF020166
+#define OID_SKGE_RLMT_RX_HELLO_CTS             0xFF020167
+#define OID_SKGE_RLMT_TX_SP_REQ_CTS            0xFF020168
+#define OID_SKGE_RLMT_RX_SP_CTS                        0xFF020169
+
+#define OID_SKGE_RLMT_MONITOR_NUMBER   0xFF010150
+#define OID_SKGE_RLMT_MONITOR_INDEX            0xFF010151
+#define OID_SKGE_RLMT_MONITOR_ADDR             0xFF010152
+#define OID_SKGE_RLMT_MONITOR_ERRS             0xFF010153
+#define OID_SKGE_RLMT_MONITOR_TIMESTAMP        0xFF010154
+#define OID_SKGE_RLMT_MONITOR_ADMIN            0xFF010155
+
+#define OID_SKGE_TX_SW_QUEUE_LEN               0xFF020170
+#define OID_SKGE_TX_SW_QUEUE_MAX               0xFF020171
+#define OID_SKGE_TX_RETRY                              0xFF020172
+#define OID_SKGE_RX_INTR_CTS                   0xFF020173
+#define OID_SKGE_TX_INTR_CTS                   0xFF020174
+#define OID_SKGE_RX_NO_BUF_CTS                 0xFF020175
+#define OID_SKGE_TX_NO_BUF_CTS                 0xFF020176
+#define OID_SKGE_TX_USED_DESCR_NO              0xFF020177
+#define OID_SKGE_RX_DELIVERED_CTS              0xFF020178
+#define OID_SKGE_RX_OCTETS_DELIV_CTS   0xFF020179
+#define OID_SKGE_RX_HW_ERROR_CTS               0xFF02017A
+#define OID_SKGE_TX_HW_ERROR_CTS               0xFF02017B
+#define OID_SKGE_IN_ERRORS_CTS                 0xFF02017C
+#define OID_SKGE_OUT_ERROR_CTS                 0xFF02017D
+#define OID_SKGE_ERR_RECOVERY_CTS              0xFF02017E
+#define OID_SKGE_SYSUPTIME                             0xFF02017F
+
+#define OID_SKGE_ALL_DATA                              0xFF020190
+
+/* Defines for VCT. */
+#define OID_SKGE_VCT_GET                               0xFF020200
+#define OID_SKGE_VCT_SET                               0xFF020201
+#define OID_SKGE_VCT_STATUS                            0xFF020202
+
+#ifdef SK_DIAG_SUPPORT
+/* Defines for driver DIAG mode. */
+#define OID_SKGE_DIAG_MODE                             0xFF020204
+#endif /* SK_DIAG_SUPPORT */
+
+/* New OIDs */
+#define OID_SKGE_DRIVER_RELDATE                        0xFF020210
+#define OID_SKGE_DRIVER_FILENAME               0xFF020211
+#define OID_SKGE_CHIPID                                        0xFF020212
+#define OID_SKGE_RAMSIZE                               0xFF020213
+#define OID_SKGE_VAUXAVAIL                             0xFF020214
+#define OID_SKGE_PHY_TYPE                              0xFF020215
+#define OID_SKGE_PHY_LP_MODE                   0xFF020216
+
+/* VCT struct to store a backup copy of VCT data after a port reset. */
+typedef struct s_PnmiVct {
+       SK_U8                   VctStatus;
+       SK_U8                   PCableLen;
+       SK_U32                  PMdiPairLen[4];
+       SK_U8                   PMdiPairSts[4];
+} SK_PNMI_VCT;
+
+
+/* VCT status values (to be given to CPA via OID_SKGE_VCT_STATUS). */
+#define SK_PNMI_VCT_NONE               0
+#define SK_PNMI_VCT_OLD_VCT_DATA       1
+#define SK_PNMI_VCT_NEW_VCT_DATA       2
+#define SK_PNMI_VCT_OLD_DSP_DATA       4
+#define SK_PNMI_VCT_NEW_DSP_DATA       8
+#define SK_PNMI_VCT_RUNNING            16
+
+
+/* VCT cable test status. */
+#define SK_PNMI_VCT_NORMAL_CABLE               0
+#define SK_PNMI_VCT_SHORT_CABLE                        1
+#define SK_PNMI_VCT_OPEN_CABLE                 2
+#define SK_PNMI_VCT_TEST_FAIL                  3
+#define SK_PNMI_VCT_IMPEDANCE_MISMATCH         4
+
+#define        OID_SKGE_TRAP_SEN_WAR_LOW               500
+#define OID_SKGE_TRAP_SEN_WAR_UPP              501
+#define        OID_SKGE_TRAP_SEN_ERR_LOW               502
+#define OID_SKGE_TRAP_SEN_ERR_UPP              503
+#define OID_SKGE_TRAP_RLMT_CHANGE_THRES        520
+#define OID_SKGE_TRAP_RLMT_CHANGE_PORT 521
+#define OID_SKGE_TRAP_RLMT_PORT_DOWN   522
+#define OID_SKGE_TRAP_RLMT_PORT_UP             523
+#define OID_SKGE_TRAP_RLMT_SEGMENTATION        524
+
+#ifdef SK_DIAG_SUPPORT
+/* Defines for driver DIAG mode. */
+#define SK_DIAG_ATTACHED       2
+#define SK_DIAG_RUNNING                1
+#define SK_DIAG_IDLE           0
+#endif /* SK_DIAG_SUPPORT */
+
+/*
+ * Generic PNMI IOCTL subcommand definitions.
+ */
+#define        SK_GET_SINGLE_VAR               1
+#define        SK_SET_SINGLE_VAR               2
+#define        SK_PRESET_SINGLE_VAR    3
+#define        SK_GET_FULL_MIB                 4
+#define        SK_SET_FULL_MIB                 5
+#define        SK_PRESET_FULL_MIB              6
+
+
+/*
+ * Define error numbers and messages for syslog
+ */
+#define SK_PNMI_ERR001         (SK_ERRBASE_PNMI + 1)
+#define SK_PNMI_ERR001MSG      "SkPnmiGetStruct: Unknown OID"
+#define SK_PNMI_ERR002         (SK_ERRBASE_PNMI + 2)
+#define SK_PNMI_ERR002MSG      "SkPnmiGetStruct: Cannot read VPD keys"
+#define SK_PNMI_ERR003         (SK_ERRBASE_PNMI + 3)
+#define SK_PNMI_ERR003MSG      "OidStruct: Called with wrong OID"
+#define SK_PNMI_ERR004         (SK_ERRBASE_PNMI + 4)
+#define SK_PNMI_ERR004MSG      "OidStruct: Called with wrong action"
+#define SK_PNMI_ERR005         (SK_ERRBASE_PNMI + 5)
+#define SK_PNMI_ERR005MSG      "Perform: Cannot reset driver"
+#define SK_PNMI_ERR006         (SK_ERRBASE_PNMI + 6)
+#define SK_PNMI_ERR006MSG      "Perform: Unknown OID action command"
+#define SK_PNMI_ERR007         (SK_ERRBASE_PNMI + 7)
+#define SK_PNMI_ERR007MSG      "General: Driver description not initialized"
+#define SK_PNMI_ERR008         (SK_ERRBASE_PNMI + 8)
+#define SK_PNMI_ERR008MSG      "Addr: Tried to get unknown OID"
+#define SK_PNMI_ERR009         (SK_ERRBASE_PNMI + 9)
+#define SK_PNMI_ERR009MSG      "Addr: Unknown OID"
+#define SK_PNMI_ERR010         (SK_ERRBASE_PNMI + 10)
+#define SK_PNMI_ERR010MSG      "CsumStat: Unknown OID"
+#define SK_PNMI_ERR011         (SK_ERRBASE_PNMI + 11)
+#define SK_PNMI_ERR011MSG      "SensorStat: Sensor descr string too long"
+#define SK_PNMI_ERR012         (SK_ERRBASE_PNMI + 12)
+#define SK_PNMI_ERR012MSG      "SensorStat: Unknown OID"
+#define SK_PNMI_ERR013         (SK_ERRBASE_PNMI + 13)
+#define SK_PNMI_ERR013MSG      ""
+#define SK_PNMI_ERR014         (SK_ERRBASE_PNMI + 14)
+#define SK_PNMI_ERR014MSG      "Vpd: Cannot read VPD keys"
+#define SK_PNMI_ERR015         (SK_ERRBASE_PNMI + 15)
+#define SK_PNMI_ERR015MSG      "Vpd: Internal array for VPD keys to small"
+#define SK_PNMI_ERR016         (SK_ERRBASE_PNMI + 16)
+#define SK_PNMI_ERR016MSG      "Vpd: Key string too long"
+#define SK_PNMI_ERR017         (SK_ERRBASE_PNMI + 17)
+#define SK_PNMI_ERR017MSG      "Vpd: Invalid VPD status pointer"
+#define SK_PNMI_ERR018         (SK_ERRBASE_PNMI + 18)
+#define SK_PNMI_ERR018MSG      "Vpd: VPD data not valid"
+#define SK_PNMI_ERR019         (SK_ERRBASE_PNMI + 19)
+#define SK_PNMI_ERR019MSG      "Vpd: VPD entries list string too long"
+#define SK_PNMI_ERR021         (SK_ERRBASE_PNMI + 21)
+#define SK_PNMI_ERR021MSG      "Vpd: VPD data string too long"
+#define SK_PNMI_ERR022         (SK_ERRBASE_PNMI + 22)
+#define SK_PNMI_ERR022MSG      "Vpd: VPD data string too long should be errored before"
+#define SK_PNMI_ERR023         (SK_ERRBASE_PNMI + 23)
+#define SK_PNMI_ERR023MSG      "Vpd: Unknown OID in get action"
+#define SK_PNMI_ERR024         (SK_ERRBASE_PNMI + 24)
+#define SK_PNMI_ERR024MSG      "Vpd: Unknown OID in preset/set action"
+#define SK_PNMI_ERR025         (SK_ERRBASE_PNMI + 25)
+#define SK_PNMI_ERR025MSG      "Vpd: Cannot write VPD after modify entry"
+#define SK_PNMI_ERR026         (SK_ERRBASE_PNMI + 26)
+#define SK_PNMI_ERR026MSG      "Vpd: Cannot update VPD"
+#define SK_PNMI_ERR027         (SK_ERRBASE_PNMI + 27)
+#define SK_PNMI_ERR027MSG      "Vpd: Cannot delete VPD entry"
+#define SK_PNMI_ERR028         (SK_ERRBASE_PNMI + 28)
+#define SK_PNMI_ERR028MSG      "Vpd: Cannot update VPD after delete entry"
+#define SK_PNMI_ERR029         (SK_ERRBASE_PNMI + 29)
+#define SK_PNMI_ERR029MSG      "General: Driver description string too long"
+#define SK_PNMI_ERR030         (SK_ERRBASE_PNMI + 30)
+#define SK_PNMI_ERR030MSG      "General: Driver version not initialized"
+#define SK_PNMI_ERR031         (SK_ERRBASE_PNMI + 31)
+#define SK_PNMI_ERR031MSG      "General: Driver version string too long"
+#define SK_PNMI_ERR032         (SK_ERRBASE_PNMI + 32)
+#define SK_PNMI_ERR032MSG      "General: Cannot read VPD Name for HW descr"
+#define SK_PNMI_ERR033         (SK_ERRBASE_PNMI + 33)
+#define SK_PNMI_ERR033MSG      "General: HW description string too long"
+#define SK_PNMI_ERR034         (SK_ERRBASE_PNMI + 34)
+#define SK_PNMI_ERR034MSG      "General: Unknown OID"
+#define SK_PNMI_ERR035         (SK_ERRBASE_PNMI + 35)
+#define SK_PNMI_ERR035MSG      "Rlmt: Unknown OID"
+#define SK_PNMI_ERR036         (SK_ERRBASE_PNMI + 36)
+#define SK_PNMI_ERR036MSG      ""
+#define SK_PNMI_ERR037         (SK_ERRBASE_PNMI + 37)
+#define SK_PNMI_ERR037MSG      "Rlmt: SK_RLMT_MODE_CHANGE event return not 0"
+#define SK_PNMI_ERR038         (SK_ERRBASE_PNMI + 38)
+#define SK_PNMI_ERR038MSG      "Rlmt: SK_RLMT_PREFPORT_CHANGE event return not 0"
+#define SK_PNMI_ERR039         (SK_ERRBASE_PNMI + 39)
+#define SK_PNMI_ERR039MSG      "RlmtStat: Unknown OID"
+#define SK_PNMI_ERR040         (SK_ERRBASE_PNMI + 40)
+#define SK_PNMI_ERR040MSG      "PowerManagement: Unknown OID"
+#define SK_PNMI_ERR041         (SK_ERRBASE_PNMI + 41)
+#define SK_PNMI_ERR041MSG      "MacPrivateConf: Unknown OID"
+#define SK_PNMI_ERR042         (SK_ERRBASE_PNMI + 42)
+#define SK_PNMI_ERR042MSG      "MacPrivateConf: SK_HWEV_SET_ROLE returned not 0"
+#define SK_PNMI_ERR043         (SK_ERRBASE_PNMI + 43)
+#define SK_PNMI_ERR043MSG      "MacPrivateConf: SK_HWEV_SET_LMODE returned not 0"
+#define SK_PNMI_ERR044         (SK_ERRBASE_PNMI + 44)
+#define SK_PNMI_ERR044MSG      "MacPrivateConf: SK_HWEV_SET_FLOWMODE returned not 0"
+#define SK_PNMI_ERR045         (SK_ERRBASE_PNMI + 45)
+#define SK_PNMI_ERR045MSG      "MacPrivateConf: SK_HWEV_SET_SPEED returned not 0"
+#define SK_PNMI_ERR046         (SK_ERRBASE_PNMI + 46)
+#define SK_PNMI_ERR046MSG      "Monitor: Unknown OID"
+#define SK_PNMI_ERR047         (SK_ERRBASE_PNMI + 47)
+#define SK_PNMI_ERR047MSG      "SirqUpdate: Event function returns not 0"
+#define SK_PNMI_ERR048         (SK_ERRBASE_PNMI + 48)
+#define SK_PNMI_ERR048MSG      "RlmtUpdate: Event function returns not 0"
+#define SK_PNMI_ERR049         (SK_ERRBASE_PNMI + 49)
+#define SK_PNMI_ERR049MSG      "SkPnmiInit: Invalid size of 'CounterOffset' struct!!"
+#define SK_PNMI_ERR050         (SK_ERRBASE_PNMI + 50)
+#define SK_PNMI_ERR050MSG      "SkPnmiInit: Invalid size of 'StatAddr' table!!"
+#define SK_PNMI_ERR051         (SK_ERRBASE_PNMI + 51)
+#define SK_PNMI_ERR051MSG      "SkPnmiEvent: Port switch suspicious"
+#define SK_PNMI_ERR052         (SK_ERRBASE_PNMI + 52)
+#define SK_PNMI_ERR052MSG      ""
+#define SK_PNMI_ERR053         (SK_ERRBASE_PNMI + 53)
+#define SK_PNMI_ERR053MSG      "General: Driver release date not initialized"
+#define SK_PNMI_ERR054         (SK_ERRBASE_PNMI + 54)
+#define SK_PNMI_ERR054MSG      "General: Driver release date string too long"
+#define SK_PNMI_ERR055         (SK_ERRBASE_PNMI + 55)
+#define SK_PNMI_ERR055MSG      "General: Driver file name not initialized"
+#define SK_PNMI_ERR056         (SK_ERRBASE_PNMI + 56)
+#define SK_PNMI_ERR056MSG      "General: Driver file name string too long"
+
+/*
+ * Management counter macros called by the driver
+ */
+#define SK_PNMI_SET_DRIVER_DESCR(pAC,v)        ((pAC)->Pnmi.pDriverDescription = \
+       (char *)(v))
+
+#define SK_PNMI_SET_DRIVER_VER(pAC,v)  ((pAC)->Pnmi.pDriverVersion = \
+       (char *)(v))
+
+#define SK_PNMI_SET_DRIVER_RELDATE(pAC,v)      ((pAC)->Pnmi.pDriverReleaseDate = \
+       (char *)(v))
+
+#define SK_PNMI_SET_DRIVER_FILENAME(pAC,v)     ((pAC)->Pnmi.pDriverFileName = \
+       (char *)(v))
+
+#define SK_PNMI_CNT_TX_QUEUE_LEN(pAC,v,p) \
+       { \
+               (pAC)->Pnmi.Port[p].TxSwQueueLen = (SK_U64)(v); \
+               if ((pAC)->Pnmi.Port[p].TxSwQueueLen > (pAC)->Pnmi.Port[p].TxSwQueueMax) { \
+                       (pAC)->Pnmi.Port[p].TxSwQueueMax = (pAC)->Pnmi.Port[p].TxSwQueueLen; \
+               } \
+       }
+#define SK_PNMI_CNT_TX_RETRY(pAC,p)    (((pAC)->Pnmi.Port[p].TxRetryCts)++)
+#define SK_PNMI_CNT_RX_INTR(pAC,p)     (((pAC)->Pnmi.Port[p].RxIntrCts)++)
+#define SK_PNMI_CNT_TX_INTR(pAC,p)     (((pAC)->Pnmi.Port[p].TxIntrCts)++)
+#define SK_PNMI_CNT_NO_RX_BUF(pAC,p)   (((pAC)->Pnmi.Port[p].RxNoBufCts)++)
+#define SK_PNMI_CNT_NO_TX_BUF(pAC,p)   (((pAC)->Pnmi.Port[p].TxNoBufCts)++)
+#define SK_PNMI_CNT_USED_TX_DESCR(pAC,v,p) \
+       ((pAC)->Pnmi.Port[p].TxUsedDescrNo=(SK_U64)(v));
+#define SK_PNMI_CNT_RX_OCTETS_DELIVERED(pAC,v,p) \
+       { \
+               ((pAC)->Pnmi.Port[p].RxDeliveredCts)++; \
+               (pAC)->Pnmi.Port[p].RxOctetsDeliveredCts += (SK_U64)(v); \
+       }
+#define SK_PNMI_CNT_ERR_RECOVERY(pAC,p)        (((pAC)->Pnmi.Port[p].ErrRecoveryCts)++);
+
+#define SK_PNMI_CNT_SYNC_OCTETS(pAC,p,v) \
+       { \
+               if ((p) < SK_MAX_MACS) { \
+                       ((pAC)->Pnmi.Port[p].StatSyncCts)++; \
+                       (pAC)->Pnmi.Port[p].StatSyncOctetsCts += (SK_U64)(v); \
+               } \
+       }
+
+#define SK_PNMI_CNT_RX_LONGFRAMES(pAC,p) \
+       { \
+               if ((p) < SK_MAX_MACS) { \
+                       ((pAC)->Pnmi.Port[p].StatRxLongFrameCts++); \
+               } \
+       }
+
+#define SK_PNMI_CNT_RX_FRAMETOOLONG(pAC,p) \
+       { \
+               if ((p) < SK_MAX_MACS) { \
+                       ((pAC)->Pnmi.Port[p].StatRxFrameTooLongCts++); \
+               } \
+       }
+
+#define SK_PNMI_CNT_RX_PMACC_ERR(pAC,p) \
+       { \
+               if ((p) < SK_MAX_MACS) { \
+                       ((pAC)->Pnmi.Port[p].StatRxPMaccErr++); \
+               } \
+       }
+
+/*
+ * Conversion Macros
+ */
+#define SK_PNMI_PORT_INST2LOG(i)       ((unsigned int)(i) - 1)
+#define SK_PNMI_PORT_LOG2INST(l)       ((unsigned int)(l) + 1)
+#define SK_PNMI_PORT_PHYS2LOG(p)       ((unsigned int)(p) + 1)
+#define SK_PNMI_PORT_LOG2PHYS(pAC,l)   ((unsigned int)(l) - 1)
+#define SK_PNMI_PORT_PHYS2INST(pAC,p)  \
+       (pAC->Pnmi.DualNetActiveFlag ? 2 : ((unsigned int)(p) + 2))
+#define SK_PNMI_PORT_INST2PHYS(pAC,i)  ((unsigned int)(i) - 2)
+
+/*
+ * Structure definition for SkPnmiGetStruct and SkPnmiSetStruct
+ */
+#define SK_PNMI_VPD_KEY_SIZE   5
+#define SK_PNMI_VPD_BUFSIZE            (VPD_SIZE)
+#define SK_PNMI_VPD_ENTRIES            (VPD_SIZE / 4)
+#define SK_PNMI_VPD_DATALEN            128 /*  Number of data bytes */
+
+#define SK_PNMI_MULTICAST_LISTLEN      64
+#define SK_PNMI_SENSOR_ENTRIES         (SK_MAX_SENSORS)
+#define SK_PNMI_CHECKSUM_ENTRIES       3
+#define SK_PNMI_MAC_ENTRIES                    (SK_MAX_MACS + 1)
+#define SK_PNMI_MONITOR_ENTRIES                20
+#define SK_PNMI_TRAP_ENTRIES           10
+#define SK_PNMI_TRAPLEN                                128
+#define SK_PNMI_STRINGLEN1                     80
+#define SK_PNMI_STRINGLEN2                     25
+#define SK_PNMI_TRAP_QUEUE_LEN         512
+
+typedef struct s_PnmiVpd {
+       char                    VpdKey[SK_PNMI_VPD_KEY_SIZE];
+       char                    VpdValue[SK_PNMI_VPD_DATALEN];
+       SK_U8                   VpdAccess;
+       SK_U8                   VpdAction;
+} SK_PNMI_VPD;
+
+typedef struct s_PnmiSensor {
+       SK_U8                   SensorIndex;
+       char                    SensorDescr[SK_PNMI_STRINGLEN2];
+       SK_U8                   SensorType;
+       SK_U32                  SensorValue;
+       SK_U32                  SensorWarningThresholdLow;
+       SK_U32                  SensorWarningThresholdHigh;
+       SK_U32                  SensorErrorThresholdLow;
+       SK_U32                  SensorErrorThresholdHigh;
+       SK_U8                   SensorStatus;
+       SK_U64                  SensorWarningCts;
+       SK_U64                  SensorErrorCts;
+       SK_U64                  SensorWarningTimestamp;
+       SK_U64                  SensorErrorTimestamp;
+} SK_PNMI_SENSOR;
+
+typedef struct s_PnmiChecksum {
+       SK_U64                  ChecksumRxOkCts;
+       SK_U64                  ChecksumRxUnableCts;
+       SK_U64                  ChecksumRxErrCts;
+       SK_U64                  ChecksumTxOkCts;
+       SK_U64                  ChecksumTxUnableCts;
+} SK_PNMI_CHECKSUM;
+
+typedef struct s_PnmiStat {
+       SK_U64                  StatTxOkCts;
+       SK_U64                  StatTxOctetsOkCts;
+       SK_U64                  StatTxBroadcastOkCts;
+       SK_U64                  StatTxMulticastOkCts;
+       SK_U64                  StatTxUnicastOkCts;
+       SK_U64                  StatTxLongFramesCts;
+       SK_U64                  StatTxBurstCts;
+       SK_U64                  StatTxPauseMacCtrlCts;
+       SK_U64                  StatTxMacCtrlCts;
+       SK_U64                  StatTxSingleCollisionCts;
+       SK_U64                  StatTxMultipleCollisionCts;
+       SK_U64                  StatTxExcessiveCollisionCts;
+       SK_U64                  StatTxLateCollisionCts;
+       SK_U64                  StatTxDeferralCts;
+       SK_U64                  StatTxExcessiveDeferralCts;
+       SK_U64                  StatTxFifoUnderrunCts;
+       SK_U64                  StatTxCarrierCts;
+       SK_U64                  Dummy1; /* StatTxUtilization */
+       SK_U64                  StatTx64Cts;
+       SK_U64                  StatTx127Cts;
+       SK_U64                  StatTx255Cts;
+       SK_U64                  StatTx511Cts;
+       SK_U64                  StatTx1023Cts;
+       SK_U64                  StatTxMaxCts;
+       SK_U64                  StatTxSyncCts;
+       SK_U64                  StatTxSyncOctetsCts;
+       SK_U64                  StatRxOkCts;
+       SK_U64                  StatRxOctetsOkCts;
+       SK_U64                  StatRxBroadcastOkCts;
+       SK_U64                  StatRxMulticastOkCts;
+       SK_U64                  StatRxUnicastOkCts;
+       SK_U64                  StatRxLongFramesCts;
+       SK_U64                  StatRxPauseMacCtrlCts;
+       SK_U64                  StatRxMacCtrlCts;
+       SK_U64                  StatRxPauseMacCtrlErrorCts;
+       SK_U64                  StatRxMacCtrlUnknownCts;
+       SK_U64                  StatRxBurstCts;
+       SK_U64                  StatRxMissedCts;
+       SK_U64                  StatRxFramingCts;
+       SK_U64                  StatRxFifoOverflowCts;
+       SK_U64                  StatRxJabberCts;
+       SK_U64                  StatRxCarrierCts;
+       SK_U64                  StatRxIRLengthCts;
+       SK_U64                  StatRxSymbolCts;
+       SK_U64                  StatRxShortsCts;
+       SK_U64                  StatRxRuntCts;
+       SK_U64                  StatRxCextCts;
+       SK_U64                  StatRxTooLongCts;
+       SK_U64                  StatRxFcsCts;
+       SK_U64                  Dummy2; /* StatRxUtilization */
+       SK_U64                  StatRx64Cts;
+       SK_U64                  StatRx127Cts;
+       SK_U64                  StatRx255Cts;
+       SK_U64                  StatRx511Cts;
+       SK_U64                  StatRx1023Cts;
+       SK_U64                  StatRxMaxCts;
+} SK_PNMI_STAT;
+
+typedef struct s_PnmiConf {
+       char                    ConfMacCurrentAddr[6];
+       char                    ConfMacFactoryAddr[6];
+       SK_U8                   ConfPMD;
+       SK_U8                   ConfConnector;
+       SK_U32                  ConfPhyType;
+       SK_U32                  ConfPhyMode;
+       SK_U8                   ConfLinkCapability;
+       SK_U8                   ConfLinkMode;
+       SK_U8                   ConfLinkModeStatus;
+       SK_U8                   ConfLinkStatus;
+       SK_U8                   ConfFlowCtrlCapability;
+       SK_U8                   ConfFlowCtrlMode;
+       SK_U8                   ConfFlowCtrlStatus;
+       SK_U8                   ConfPhyOperationCapability;
+       SK_U8                   ConfPhyOperationMode;
+       SK_U8                   ConfPhyOperationStatus;
+       SK_U8                   ConfSpeedCapability;
+       SK_U8                   ConfSpeedMode;
+       SK_U8                   ConfSpeedStatus;
+} SK_PNMI_CONF;
+
+typedef struct s_PnmiRlmt {
+       SK_U32                  RlmtIndex;
+       SK_U32                  RlmtStatus;
+       SK_U64                  RlmtTxHelloCts;
+       SK_U64                  RlmtRxHelloCts;
+       SK_U64                  RlmtTxSpHelloReqCts;
+       SK_U64                  RlmtRxSpHelloCts;
+} SK_PNMI_RLMT;
+
+typedef struct s_PnmiRlmtMonitor {
+       SK_U32                  RlmtMonitorIndex;
+       char                    RlmtMonitorAddr[6];
+       SK_U64                  RlmtMonitorErrorCts;
+       SK_U64                  RlmtMonitorTimestamp;
+       SK_U8                   RlmtMonitorAdmin;
+} SK_PNMI_RLMT_MONITOR;
+
+typedef struct s_PnmiRequestStatus {
+       SK_U32                  ErrorStatus;
+       SK_U32                  ErrorOffset;
+} SK_PNMI_REQUEST_STATUS;
+
+typedef struct s_PnmiStrucData {
+       SK_U32                  MgmtDBVersion;
+       SK_PNMI_REQUEST_STATUS  ReturnStatus;
+       SK_U32                  VpdFreeBytes;
+       char                    VpdEntriesList[SK_PNMI_VPD_ENTRIES * SK_PNMI_VPD_KEY_SIZE];
+       SK_U32                  VpdEntriesNumber;
+       SK_PNMI_VPD             Vpd[SK_PNMI_VPD_ENTRIES];
+       SK_U32                  PortNumber;
+       SK_U32                  DeviceType;
+       char                    DriverDescr[SK_PNMI_STRINGLEN1];
+       char                    DriverVersion[SK_PNMI_STRINGLEN2];
+       char                    DriverReleaseDate[SK_PNMI_STRINGLEN1];
+       char                    DriverFileName[SK_PNMI_STRINGLEN1];
+       char                    HwDescr[SK_PNMI_STRINGLEN1];
+       char                    HwVersion[SK_PNMI_STRINGLEN2];
+       SK_U16                  Chipset;
+       SK_U32                  ChipId;
+       SK_U8                   VauxAvail;
+       SK_U32                  RamSize;
+       SK_U32                  MtuSize;
+       SK_U32                  Action;
+       SK_U32                  TestResult;
+       SK_U8                   BusType;
+       SK_U8                   BusSpeed;
+       SK_U8                   BusWidth;
+       SK_U8                   SensorNumber;
+       SK_PNMI_SENSOR  Sensor[SK_PNMI_SENSOR_ENTRIES];
+       SK_U8                   ChecksumNumber;
+       SK_PNMI_CHECKSUM        Checksum[SK_PNMI_CHECKSUM_ENTRIES];
+       SK_PNMI_STAT    Stat[SK_PNMI_MAC_ENTRIES];
+       SK_PNMI_CONF    Conf[SK_PNMI_MAC_ENTRIES];
+       SK_U8                   RlmtMode;
+       SK_U32                  RlmtPortNumber;
+       SK_U8                   RlmtPortActive;
+       SK_U8                   RlmtPortPreferred;
+       SK_U64                  RlmtChangeCts;
+       SK_U64                  RlmtChangeTime;
+       SK_U64                  RlmtChangeEstimate;
+       SK_U64                  RlmtChangeThreshold;
+       SK_PNMI_RLMT    Rlmt[SK_MAX_MACS];
+       SK_U32                  RlmtMonitorNumber;
+       SK_PNMI_RLMT_MONITOR    RlmtMonitor[SK_PNMI_MONITOR_ENTRIES];
+       SK_U32                  TrapNumber;
+       SK_U8                   Trap[SK_PNMI_TRAP_QUEUE_LEN];
+       SK_U64                  TxSwQueueLen;
+       SK_U64                  TxSwQueueMax;
+       SK_U64                  TxRetryCts;
+       SK_U64                  RxIntrCts;
+       SK_U64                  TxIntrCts;
+       SK_U64                  RxNoBufCts;
+       SK_U64                  TxNoBufCts;
+       SK_U64                  TxUsedDescrNo;
+       SK_U64                  RxDeliveredCts;
+       SK_U64                  RxOctetsDeliveredCts;
+       SK_U64                  RxHwErrorsCts;
+       SK_U64                  TxHwErrorsCts;
+       SK_U64                  InErrorsCts;
+       SK_U64                  OutErrorsCts;
+       SK_U64                  ErrRecoveryCts;
+       SK_U64                  SysUpTime;
+} SK_PNMI_STRUCT_DATA;
+
+#define SK_PNMI_STRUCT_SIZE    (sizeof(SK_PNMI_STRUCT_DATA))
+#define SK_PNMI_MIN_STRUCT_SIZE        ((unsigned int)(SK_UPTR)\
+                                &(((SK_PNMI_STRUCT_DATA *)0)->VpdFreeBytes))
+                                                                                                               /*
+                                                                                                                * ReturnStatus field
+                                                                                                                * must be located
+                                                                                                                * before VpdFreeBytes
+                                                                                                                */
+
+/*
+ * Various definitions
+ */
+#define SK_PNMI_MAX_PROTOS             3
+
+#define SK_PNMI_CNT_NO                 66      /* Must have the value of the enum
+                                                                        * SK_PNMI_MAX_IDX. Define SK_PNMI_CHECK
+                                                                        * for check while init phase 1
+                                                                        */
+
+/*
+ * Estimate data structure
+ */
+typedef struct s_PnmiEstimate {
+       unsigned int    EstValueIndex;
+       SK_U64                  EstValue[7];
+       SK_U64                  Estimate;
+       SK_TIMER                EstTimer;
+} SK_PNMI_ESTIMATE;
+
+
+/*
+ * VCT timer data structure
+ */
+typedef struct s_VctTimer {
+       SK_TIMER                VctTimer;
+} SK_PNMI_VCT_TIMER;
+
+
+/*
+ * PNMI specific adapter context structure
+ */
+typedef struct s_PnmiPort {
+       SK_U64                  StatSyncCts;
+       SK_U64                  StatSyncOctetsCts;
+       SK_U64                  StatRxLongFrameCts;
+       SK_U64                  StatRxFrameTooLongCts;
+       SK_U64                  StatRxPMaccErr;
+       SK_U64                  TxSwQueueLen;
+       SK_U64                  TxSwQueueMax;
+       SK_U64                  TxRetryCts;
+       SK_U64                  RxIntrCts;
+       SK_U64                  TxIntrCts;
+       SK_U64                  RxNoBufCts;
+       SK_U64                  TxNoBufCts;
+       SK_U64                  TxUsedDescrNo;
+       SK_U64                  RxDeliveredCts;
+       SK_U64                  RxOctetsDeliveredCts;
+       SK_U64                  RxHwErrorsCts;
+       SK_U64                  TxHwErrorsCts;
+       SK_U64                  InErrorsCts;
+       SK_U64                  OutErrorsCts;
+       SK_U64                  ErrRecoveryCts;
+       SK_U64                  RxShortZeroMark;
+       SK_U64                  CounterOffset[SK_PNMI_CNT_NO];
+       SK_U32                  CounterHigh[SK_PNMI_CNT_NO];
+       SK_BOOL                 ActiveFlag;
+       SK_U8                   Align[3];
+} SK_PNMI_PORT;
+
+
+typedef struct s_PnmiData {
+       SK_PNMI_PORT    Port    [SK_MAX_MACS];
+       SK_PNMI_PORT    BufPort [SK_MAX_MACS]; /* 2002-09-13 pweber  */
+       SK_U64                  VirtualCounterOffset[SK_PNMI_CNT_NO];
+       SK_U32                  TestResult;
+       char                    HwVersion[10];
+       SK_U16                  Align01;
+
+       char                    *pDriverDescription;
+       char                    *pDriverVersion;
+       char                    *pDriverReleaseDate;
+       char                    *pDriverFileName;
+
+       int                             MacUpdatedFlag;
+       int                             RlmtUpdatedFlag;
+       int                             SirqUpdatedFlag;
+
+       SK_U64                  RlmtChangeCts;
+       SK_U64                  RlmtChangeTime;
+       SK_PNMI_ESTIMATE        RlmtChangeEstimate;
+       SK_U64                  RlmtChangeThreshold;
+
+       SK_U64                  StartUpTime;
+       SK_U32                  DeviceType;
+       char                    PciBusSpeed;
+       char                    PciBusWidth;
+       char                    Chipset;
+       char                    PMD;
+       char                    Connector;
+       SK_BOOL                 DualNetActiveFlag;
+       SK_U16                  Align02;
+
+       char                    TrapBuf[SK_PNMI_TRAP_QUEUE_LEN];
+       unsigned int    TrapBufFree;
+       unsigned int    TrapQueueBeg;
+       unsigned int    TrapQueueEnd;
+       unsigned int    TrapBufPad;
+       unsigned int    TrapUnique;
+       SK_U8           VctStatus[SK_MAX_MACS];
+       SK_PNMI_VCT     VctBackup[SK_MAX_MACS];
+       SK_PNMI_VCT_TIMER VctTimeout[SK_MAX_MACS];
+#ifdef SK_DIAG_SUPPORT
+       SK_U32                  DiagAttached;
+#endif /* SK_DIAG_SUPPORT */
+} SK_PNMI;
+
+
+/*
+ * Function prototypes
+ */
+extern int SkPnmiInit(SK_AC *pAC, SK_IOC IoC, int Level);
+extern int SkPnmiSetVar(SK_AC *pAC, SK_IOC IoC, SK_U32 Id, void* pBuf,
+       unsigned int *pLen, SK_U32 Instance, SK_U32 NetIndex);
+extern int SkPnmiGetStruct(SK_AC *pAC, SK_IOC IoC, void* pBuf,
+       unsigned int *pLen, SK_U32 NetIndex);
+extern int SkPnmiPreSetStruct(SK_AC *pAC, SK_IOC IoC, void* pBuf,
+       unsigned int *pLen, SK_U32 NetIndex);
+extern int SkPnmiSetStruct(SK_AC *pAC, SK_IOC IoC, void* pBuf,
+       unsigned int *pLen, SK_U32 NetIndex);
+extern int SkPnmiEvent(SK_AC *pAC, SK_IOC IoC, SK_U32 Event,
+       SK_EVPARA Param);
+extern int SkPnmiGenIoctl(SK_AC *pAC, SK_IOC IoC, void * pBuf,
+       unsigned int * pLen, SK_U32 NetIndex);
+
+#endif
diff --git a/drivers/net/sk98lin/h/skgesirq.h b/drivers/net/sk98lin/h/skgesirq.h
new file mode 100644 (file)
index 0000000..3eec627
--- /dev/null
@@ -0,0 +1,110 @@
+/******************************************************************************
+ *
+ * Name:       skgesirq.h
+ * Project:    Gigabit Ethernet Adapters, Common Modules
+ * Version:    $Revision: 1.30 $
+ * Date:       $Date: 2003/07/04 12:34:13 $
+ * Purpose:    SK specific Gigabit Ethernet special IRQ functions
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *     (C)Copyright 1998-2002 SysKonnect.
+ *     (C)Copyright 2002-2003 Marvell.
+ *
+ *     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.
+ *
+ *     The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+#ifndef _INC_SKGESIRQ_H_
+#define _INC_SKGESIRQ_H_
+
+/* Define return codes of SkGePortCheckUp and CheckShort */
+#define        SK_HW_PS_NONE           0       /* No action needed */
+#define        SK_HW_PS_RESTART        1       /* Restart needed */
+#define        SK_HW_PS_LINK           2       /* Link Up actions needed */
+
+/*
+ * Define the Event the special IRQ/INI module can handle
+ */
+#define SK_HWEV_WATIM                  1       /* Timeout for WA Errata #2 XMAC */
+#define SK_HWEV_PORT_START             2       /* Port Start Event by RLMT */
+#define SK_HWEV_PORT_STOP              3       /* Port Stop Event by RLMT */
+#define SK_HWEV_CLEAR_STAT             4       /* Clear Statistics by PNMI */
+#define SK_HWEV_UPDATE_STAT            5       /* Update Statistics by PNMI */
+#define SK_HWEV_SET_LMODE              6       /* Set Link Mode by PNMI */
+#define SK_HWEV_SET_FLOWMODE   7       /* Set Flow Control Mode by PNMI */
+#define SK_HWEV_SET_ROLE               8       /* Set Master/Slave (Role) by PNMI */
+#define SK_HWEV_SET_SPEED              9       /* Set Link Speed by PNMI */
+#define SK_HWEV_HALFDUP_CHK            10      /* Half Duplex Hangup Workaround */
+
+#define SK_WA_ACT_TIME         (5000000UL)     /* 5 sec */
+#define SK_WA_INA_TIME         (100000UL)      /* 100 msec */
+
+#define SK_HALFDUP_CHK_TIME    (10000UL)       /* 10 msec */
+
+/*
+ * Define the error numbers and messages
+ */
+#define SKERR_SIRQ_E001                (SK_ERRBASE_SIRQ+0)
+#define SKERR_SIRQ_E001MSG     "Unknown event"
+#define SKERR_SIRQ_E002                (SKERR_SIRQ_E001+1)
+#define SKERR_SIRQ_E002MSG     "Packet timeout RX1"
+#define SKERR_SIRQ_E003                (SKERR_SIRQ_E002+1)
+#define SKERR_SIRQ_E003MSG     "Packet timeout RX2"
+#define SKERR_SIRQ_E004                (SKERR_SIRQ_E003+1)
+#define SKERR_SIRQ_E004MSG     "MAC 1 not correctly initialized"
+#define SKERR_SIRQ_E005                (SKERR_SIRQ_E004+1)
+#define SKERR_SIRQ_E005MSG     "MAC 2 not correctly initialized"
+#define SKERR_SIRQ_E006                (SKERR_SIRQ_E005+1)
+#define SKERR_SIRQ_E006MSG     "CHECK failure R1"
+#define SKERR_SIRQ_E007                (SKERR_SIRQ_E006+1)
+#define SKERR_SIRQ_E007MSG     "CHECK failure R2"
+#define SKERR_SIRQ_E008                (SKERR_SIRQ_E007+1)
+#define SKERR_SIRQ_E008MSG     "CHECK failure XS1"
+#define SKERR_SIRQ_E009                (SKERR_SIRQ_E008+1)
+#define SKERR_SIRQ_E009MSG     "CHECK failure XA1"
+#define SKERR_SIRQ_E010                (SKERR_SIRQ_E009+1)
+#define SKERR_SIRQ_E010MSG     "CHECK failure XS2"
+#define SKERR_SIRQ_E011                (SKERR_SIRQ_E010+1)
+#define SKERR_SIRQ_E011MSG     "CHECK failure XA2"
+#define SKERR_SIRQ_E012                (SKERR_SIRQ_E011+1)
+#define SKERR_SIRQ_E012MSG     "unexpected IRQ Master error"
+#define SKERR_SIRQ_E013                (SKERR_SIRQ_E012+1)
+#define SKERR_SIRQ_E013MSG     "unexpected IRQ Status error"
+#define SKERR_SIRQ_E014                (SKERR_SIRQ_E013+1)
+#define SKERR_SIRQ_E014MSG     "Parity error on RAM (read)"
+#define SKERR_SIRQ_E015                (SKERR_SIRQ_E014+1)
+#define SKERR_SIRQ_E015MSG     "Parity error on RAM (write)"
+#define SKERR_SIRQ_E016                (SKERR_SIRQ_E015+1)
+#define SKERR_SIRQ_E016MSG     "Parity error MAC 1"
+#define SKERR_SIRQ_E017                (SKERR_SIRQ_E016+1)
+#define SKERR_SIRQ_E017MSG     "Parity error MAC 2"
+#define SKERR_SIRQ_E018                (SKERR_SIRQ_E017+1)
+#define SKERR_SIRQ_E018MSG     "Parity error RX 1"
+#define SKERR_SIRQ_E019                (SKERR_SIRQ_E018+1)
+#define SKERR_SIRQ_E019MSG     "Parity error RX 2"
+#define SKERR_SIRQ_E020                (SKERR_SIRQ_E019+1)
+#define SKERR_SIRQ_E020MSG     "MAC transmit FIFO underrun"
+#define SKERR_SIRQ_E021                (SKERR_SIRQ_E020+1)
+#define SKERR_SIRQ_E021MSG     "Spurious TWSI interrupt"
+#define SKERR_SIRQ_E022                (SKERR_SIRQ_E021+1)
+#define SKERR_SIRQ_E022MSG     "Cable pair swap error"
+#define SKERR_SIRQ_E023                (SKERR_SIRQ_E022+1)
+#define SKERR_SIRQ_E023MSG     "Auto-negotiation error"
+#define SKERR_SIRQ_E024                (SKERR_SIRQ_E023+1)
+#define SKERR_SIRQ_E024MSG     "FIFO overflow error"
+#define SKERR_SIRQ_E025                (SKERR_SIRQ_E024+1)
+#define SKERR_SIRQ_E025MSG     "2 Pair Downshift detected"
+
+extern void SkGeSirqIsr(SK_AC *pAC, SK_IOC IoC, SK_U32 Istatus);
+extern int  SkGeSirqEvent(SK_AC *pAC, SK_IOC IoC, SK_U32 Event, SK_EVPARA Para);
+extern void SkHWLinkDown(SK_AC *pAC, SK_IOC IoC, int Port);
+
+#endif /* _INC_SKGESIRQ_H_ */
diff --git a/drivers/net/sk98lin/h/ski2c.h b/drivers/net/sk98lin/h/ski2c.h
new file mode 100644 (file)
index 0000000..6a63f4a
--- /dev/null
@@ -0,0 +1,174 @@
+/******************************************************************************
+ *
+ * Name:       ski2c.h
+ * Project:    Gigabit Ethernet Adapters, TWSI-Module
+ * Version:    $Revision: 1.35 $
+ * Date:       $Date: 2003/10/20 09:06:30 $
+ * Purpose:    Defines to access Voltage and Temperature Sensor
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *     (C)Copyright 1998-2002 SysKonnect.
+ *     (C)Copyright 2002-2003 Marvell.
+ *
+ *     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.
+ *
+ *     The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/*
+ * SKI2C.H     contains all I2C specific defines
+ */
+
+#ifndef _SKI2C_H_
+#define _SKI2C_H_
+
+typedef struct  s_Sensor SK_SENSOR;
+
+#include "h/skgei2c.h"
+
+/*
+ * Define the I2C events.
+ */
+#define SK_I2CEV_IRQ   1       /* IRQ happened Event */
+#define SK_I2CEV_TIM   2       /* Timeout event */
+#define SK_I2CEV_CLEAR 3       /* Clear MIB Values */
+
+/*
+ * Define READ and WRITE Constants.
+ */
+#define I2C_READ       0
+#define I2C_WRITE      1
+#define I2C_BURST      1
+#define I2C_SINGLE     0
+
+#define SKERR_I2C_E001         (SK_ERRBASE_I2C+0)
+#define SKERR_I2C_E001MSG      "Sensor index unknown"
+#define SKERR_I2C_E002         (SKERR_I2C_E001+1)
+#define SKERR_I2C_E002MSG      "TWSI: transfer does not complete"
+#define SKERR_I2C_E003         (SKERR_I2C_E002+1)
+#define SKERR_I2C_E003MSG      "LM80: NAK on device send"
+#define SKERR_I2C_E004         (SKERR_I2C_E003+1)
+#define SKERR_I2C_E004MSG      "LM80: NAK on register send"
+#define SKERR_I2C_E005         (SKERR_I2C_E004+1)
+#define SKERR_I2C_E005MSG      "LM80: NAK on device (2) send"
+#define SKERR_I2C_E006         (SKERR_I2C_E005+1)
+#define SKERR_I2C_E006MSG      "Unknown event"
+#define SKERR_I2C_E007         (SKERR_I2C_E006+1)
+#define SKERR_I2C_E007MSG      "LM80 read out of state"
+#define SKERR_I2C_E008         (SKERR_I2C_E007+1)
+#define SKERR_I2C_E008MSG      "Unexpected sensor read completed"
+#define SKERR_I2C_E009         (SKERR_I2C_E008+1)
+#define SKERR_I2C_E009MSG      "WARNING: temperature sensor out of range"
+#define SKERR_I2C_E010         (SKERR_I2C_E009+1)
+#define SKERR_I2C_E010MSG      "WARNING: voltage sensor out of range"
+#define SKERR_I2C_E011         (SKERR_I2C_E010+1)
+#define SKERR_I2C_E011MSG      "ERROR: temperature sensor out of range"
+#define SKERR_I2C_E012         (SKERR_I2C_E011+1)
+#define SKERR_I2C_E012MSG      "ERROR: voltage sensor out of range"
+#define SKERR_I2C_E013         (SKERR_I2C_E012+1)
+#define SKERR_I2C_E013MSG      "ERROR: couldn't init sensor"
+#define SKERR_I2C_E014         (SKERR_I2C_E013+1)
+#define SKERR_I2C_E014MSG      "WARNING: fan sensor out of range"
+#define SKERR_I2C_E015         (SKERR_I2C_E014+1)
+#define SKERR_I2C_E015MSG      "ERROR: fan sensor out of range"
+#define SKERR_I2C_E016         (SKERR_I2C_E015+1)
+#define SKERR_I2C_E016MSG      "TWSI: active transfer does not complete"
+
+/*
+ * Define Timeout values
+ */
+#define SK_I2C_TIM_LONG                2000000L        /* 2 seconds */
+#define SK_I2C_TIM_SHORT        100000L        /* 100 milliseconds */
+#define SK_I2C_TIM_WATCH       1000000L        /* 1 second */
+
+/*
+ * Define trap and error log hold times
+ */
+#ifndef        SK_SEN_ERR_TR_HOLD
+#define SK_SEN_ERR_TR_HOLD             (4*SK_TICKS_PER_SEC)
+#endif
+#ifndef        SK_SEN_ERR_LOG_HOLD
+#define SK_SEN_ERR_LOG_HOLD            (60*SK_TICKS_PER_SEC)
+#endif
+#ifndef        SK_SEN_WARN_TR_HOLD
+#define SK_SEN_WARN_TR_HOLD            (15*SK_TICKS_PER_SEC)
+#endif
+#ifndef        SK_SEN_WARN_LOG_HOLD
+#define SK_SEN_WARN_LOG_HOLD   (15*60*SK_TICKS_PER_SEC)
+#endif
+
+/*
+ * Defines for SenType
+ */
+#define SK_SEN_UNKNOWN 0
+#define SK_SEN_TEMP            1
+#define SK_SEN_VOLT            2
+#define SK_SEN_FAN             3
+
+/*
+ * Define for the SenErrorFlag
+ */
+#define SK_SEN_ERR_NOT_PRESENT 0       /* Error Flag: Sensor not present */
+#define SK_SEN_ERR_OK                  1       /* Error Flag: O.K. */
+#define SK_SEN_ERR_WARN                        2       /* Error Flag: Warning */
+#define SK_SEN_ERR_ERR                 3       /* Error Flag: Error */
+#define SK_SEN_ERR_FAULTY              4       /* Error Flag: Faulty */
+
+/*
+ * Define the Sensor struct
+ */
+struct s_Sensor {
+       char    *SenDesc;                       /* Description */
+       int             SenType;                        /* Voltage or Temperature */
+       SK_I32  SenValue;                       /* Current value of the sensor */
+       SK_I32  SenThreErrHigh;         /* High error Threshhold of this sensor */
+       SK_I32  SenThreWarnHigh;        /* High warning Threshhold of this sensor */
+       SK_I32  SenThreErrLow;          /* Lower error Threshold of the sensor */
+       SK_I32  SenThreWarnLow;         /* Lower warning Threshold of the sensor */
+       int             SenErrFlag;                     /* Sensor indicated an error */
+       SK_BOOL SenInit;                        /* Is sensor initialized ? */
+       SK_U64  SenErrCts;                      /* Error trap counter */
+       SK_U64  SenWarnCts;                     /* Warning trap counter */
+       SK_U64  SenBegErrTS;            /* Begin error timestamp */
+       SK_U64  SenBegWarnTS;           /* Begin warning timestamp */
+       SK_U64  SenLastErrTrapTS;       /* Last error trap timestamp */
+       SK_U64  SenLastErrLogTS;        /* Last error log timestamp */
+       SK_U64  SenLastWarnTrapTS;      /* Last warning trap timestamp */
+       SK_U64  SenLastWarnLogTS;       /* Last warning log timestamp */
+       int             SenState;                       /* Sensor State (see HW specific include) */
+       int             (*SenRead)(SK_AC *pAC, SK_IOC IoC, struct s_Sensor *pSen);
+                                                               /* Sensors read function */
+       SK_U16  SenReg;                         /* Register Address for this sensor */
+       SK_U8   SenDev;                         /* Device Selection for this sensor */
+};
+
+typedef        struct  s_I2c {
+       SK_SENSOR       SenTable[SK_MAX_SENSORS];       /* Sensor Table */
+       int                     CurrSens;       /* Which sensor is currently queried */
+       int                     MaxSens;        /* Max. number of sensors */
+       int                     TimerMode;      /* Use the timer also to watch the state machine */
+       int                     InitLevel;      /* Initialized Level */
+#ifndef SK_DIAG
+       int                     DummyReads;     /* Number of non-checked dummy reads */
+       SK_TIMER        SenTimer;       /* Sensors timer */
+#endif /* !SK_DIAG */
+} SK_I2C;
+
+extern int SkI2cInit(SK_AC *pAC, SK_IOC IoC, int Level);
+#ifdef SK_DIAG
+extern SK_U32 SkI2cRead(SK_AC *pAC, SK_IOC IoC, int Dev, int Size, int Reg,
+                                                int Burst);
+#else /* !SK_DIAG */
+extern int SkI2cEvent(SK_AC *pAC, SK_IOC IoC, SK_U32 Event, SK_EVPARA Para);
+extern void SkI2cWaitIrq(SK_AC *pAC, SK_IOC IoC);
+extern void SkI2cIsr(SK_AC *pAC, SK_IOC IoC);
+#endif /* !SK_DIAG */
+#endif /* n_SKI2C_H */
+
diff --git a/drivers/net/sk98lin/h/skqueue.h b/drivers/net/sk98lin/h/skqueue.h
new file mode 100644 (file)
index 0000000..2ec40d4
--- /dev/null
@@ -0,0 +1,94 @@
+/******************************************************************************
+ *
+ * Name:       skqueue.h
+ * Project:    Gigabit Ethernet Adapters, Event Scheduler Module
+ * Version:    $Revision: 1.16 $
+ * Date:       $Date: 2003/09/16 12:50:32 $
+ * Purpose:    Defines for the Event queue
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *     (C)Copyright 1998-2002 SysKonnect GmbH.
+ *     (C)Copyright 2002-2003 Marvell.
+ *
+ *     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.
+ *
+ *     The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/*
+ * SKQUEUE.H   contains all defines and types for the event queue
+ */
+
+#ifndef _SKQUEUE_H_
+#define _SKQUEUE_H_
+
+
+/*
+ * define the event classes to be served
+ */
+#define        SKGE_DRV        1       /* Driver Event Class */
+#define        SKGE_RLMT       2       /* RLMT Event Class */
+#define        SKGE_I2C        3       /* I2C Event Class */
+#define        SKGE_PNMI       4       /* PNMI Event Class */
+#define        SKGE_CSUM       5       /* Checksum Event Class */
+#define        SKGE_HWAC       6       /* Hardware Access Event Class */
+
+#define        SKGE_SWT        9       /* Software Timer Event Class */
+#define        SKGE_LACP       10      /* LACP Aggregation Event Class */
+#define        SKGE_RSF        11      /* RSF Aggregation Event Class */
+#define        SKGE_MARKER     12      /* MARKER Aggregation Event Class */
+#define        SKGE_FD         13      /* FD Distributor Event Class */
+
+/*
+ * define event queue as circular buffer
+ */
+#define SK_MAX_EVENT   64
+
+/*
+ * Parameter union for the Para stuff
+ */
+typedef        union u_EvPara {
+       void    *pParaPtr;      /* Parameter Pointer */
+       SK_U64  Para64;         /* Parameter 64bit version */
+       SK_U32  Para32[2];      /* Parameter Array of 32bit parameters */
+} SK_EVPARA;
+
+/*
+ * Event Queue
+ *     skqueue.c
+ * events are class/value pairs
+ *     class   is addressee, e.g. RLMT, PNMI etc.
+ *     value   is command, e.g. line state change, ring op change etc.
+ */
+typedef        struct s_EventElem {
+       SK_U32          Class;                  /* Event class */
+       SK_U32          Event;                  /* Event value */
+       SK_EVPARA       Para;                   /* Event parameter */
+} SK_EVENTELEM;
+
+typedef        struct s_Queue {
+       SK_EVENTELEM    EvQueue[SK_MAX_EVENT];
+       SK_EVENTELEM    *EvPut;
+       SK_EVENTELEM    *EvGet;
+} SK_QUEUE;
+
+extern void SkEventInit(SK_AC *pAC, SK_IOC Ioc, int Level);
+extern void SkEventQueue(SK_AC *pAC, SK_U32 Class, SK_U32 Event,
+       SK_EVPARA Para);
+extern int SkEventDispatcher(SK_AC *pAC, SK_IOC Ioc);
+
+
+/* Define Error Numbers and messages */
+#define        SKERR_Q_E001    (SK_ERRBASE_QUEUE+0)
+#define        SKERR_Q_E001MSG "Event queue overflow"
+#define        SKERR_Q_E002    (SKERR_Q_E001+1)
+#define        SKERR_Q_E002MSG "Undefined event class"
+#endif /* _SKQUEUE_H_ */
+
diff --git a/drivers/net/sk98lin/h/skrlmt.h b/drivers/net/sk98lin/h/skrlmt.h
new file mode 100644 (file)
index 0000000..ca75dfd
--- /dev/null
@@ -0,0 +1,438 @@
+/******************************************************************************
+ *
+ * Name:       skrlmt.h
+ * Project:    GEnesis, PCI Gigabit Ethernet Adapter
+ * Version:    $Revision: 1.37 $
+ * Date:       $Date: 2003/04/15 09:43:43 $
+ * Purpose:    Header file for Redundant Link ManagemenT.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *     (C)Copyright 1998-2002 SysKonnect GmbH.
+ *     (C)Copyright 2002-2003 Marvell.
+ *
+ *     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.
+ *
+ *     The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * Description:
+ *
+ * This is the header file for Redundant Link ManagemenT.
+ *
+ * Include File Hierarchy:
+ *
+ *     "skdrv1st.h"
+ *     ...
+ *     "sktypes.h"
+ *     "skqueue.h"
+ *     "skaddr.h"
+ *     "skrlmt.h"
+ *     ...
+ *     "skdrv2nd.h"
+ *
+ ******************************************************************************/
+
+#ifndef __INC_SKRLMT_H
+#define __INC_SKRLMT_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* cplusplus */
+
+/* defines ********************************************************************/
+
+#define        SK_RLMT_NET_DOWN_TEMP   1       /* NET_DOWN due to last port down. */
+#define        SK_RLMT_NET_DOWN_FINAL  2       /* NET_DOWN due to RLMT_STOP. */
+
+/* ----- Default queue sizes - must be multiples of 8 KB ----- */
+
+/* Less than 8 KB free in RX queue => pause frames. */
+#define SK_RLMT_STANDBY_QRXSIZE        128     /* Size of rx standby queue in KB. */
+#define SK_RLMT_STANDBY_QXASIZE        32      /* Size of async standby queue in KB. */
+#define SK_RLMT_STANDBY_QXSSIZE        0       /* Size of sync standby queue in KB. */
+
+#define SK_RLMT_MAX_TX_BUF_SIZE        60      /* Maximum RLMT transmit size. */
+
+/* ----- PORT states ----- */
+
+#define SK_RLMT_PS_INIT                        0       /* Port state: Init. */
+#define SK_RLMT_PS_LINK_DOWN   1       /* Port state: Link down. */
+#define SK_RLMT_PS_DOWN                        2       /* Port state: Port down. */
+#define SK_RLMT_PS_GOING_UP            3       /* Port state: Going up. */
+#define SK_RLMT_PS_UP                  4       /* Port state: Up. */
+
+/* ----- RLMT states ----- */
+
+#define SK_RLMT_RS_INIT                        0       /* RLMT state: Init. */
+#define SK_RLMT_RS_NET_DOWN            1       /* RLMT state: Net down. */
+#define SK_RLMT_RS_NET_UP              2       /* RLMT state: Net up. */
+
+/* ----- PORT events ----- */
+
+#define SK_RLMT_LINK_UP                        1001    /* Link came up. */
+#define SK_RLMT_LINK_DOWN              1002    /* Link went down. */
+#define SK_RLMT_PORT_ADDR              1003    /* Port address changed. */
+
+/* ----- RLMT events ----- */
+
+#define SK_RLMT_START                  2001    /* Start RLMT. */
+#define SK_RLMT_STOP                   2002    /* Stop RLMT. */
+#define SK_RLMT_PACKET_RECEIVED        2003    /* Packet was received for RLMT. */
+#define SK_RLMT_STATS_CLEAR            2004    /* Clear statistics. */
+#define SK_RLMT_STATS_UPDATE   2005    /* Update statistics. */
+#define SK_RLMT_PREFPORT_CHANGE        2006    /* Change preferred port. */
+#define SK_RLMT_MODE_CHANGE            2007    /* New RlmtMode. */
+#define SK_RLMT_SET_NETS               2008    /* Number of Nets (1 or 2). */
+
+/* ----- RLMT mode bits ----- */
+
+/*
+ * CAUTION:    These defines are private to RLMT.
+ *                     Please use the RLMT mode defines below.
+ */
+
+#define SK_RLMT_CHECK_LINK               1             /* Check Link. */
+#define SK_RLMT_CHECK_LOC_LINK   2             /* Check other link on same adapter. */
+#define SK_RLMT_CHECK_SEG                4             /* Check segmentation. */
+
+#ifndef RLMT_CHECK_REMOTE
+#define SK_RLMT_CHECK_OTHERS   SK_RLMT_CHECK_LOC_LINK
+#else  /* RLMT_CHECK_REMOTE */
+#define SK_RLMT_CHECK_REM_LINK   8             /* Check link(s) on other adapter(s). */
+#define SK_RLMT_MAX_REMOTE_PORTS_CHECKED       3
+#define SK_RLMT_CHECK_OTHERS   \
+               (SK_RLMT_CHECK_LOC_LINK | SK_RLMT_CHECK_REM_LINK)
+#endif /* RLMT_CHECK_REMOTE */
+
+#ifndef SK_RLMT_ENABLE_TRANSPARENT
+#define SK_RLMT_TRANSPARENT              0             /* RLMT transparent - inactive. */
+#else  /* SK_RLMT_ENABLE_TRANSPARENT */
+#define SK_RLMT_TRANSPARENT            128             /* RLMT transparent. */
+#endif /* SK_RLMT_ENABLE_TRANSPARENT */
+
+/* ----- RLMT modes ----- */
+
+/* Check Link State. */
+#define SK_RLMT_MODE_CLS       (SK_RLMT_CHECK_LINK)
+
+/* Check Local Ports: check other links on the same adapter. */
+#define SK_RLMT_MODE_CLP       (SK_RLMT_CHECK_LINK | SK_RLMT_CHECK_LOC_LINK)
+
+/* Check Local Ports and Segmentation Status. */
+#define SK_RLMT_MODE_CLPSS     \
+               (SK_RLMT_CHECK_LINK | SK_RLMT_CHECK_LOC_LINK | SK_RLMT_CHECK_SEG)
+
+#ifdef RLMT_CHECK_REMOTE
+/* Check Local and Remote Ports: check links (local or remote). */
+       Name of define TBD!
+#define SK_RLMT_MODE_CRP       \
+               (SK_RLMT_CHECK_LINK | SK_RLMT_CHECK_LOC_LINK | SK_RLMT_CHECK_REM_LINK)
+
+/* Check Local and Remote Ports and Segmentation Status. */
+       Name of define TBD!
+#define SK_RLMT_MODE_CRPSS     \
+               (SK_RLMT_CHECK_LINK | SK_RLMT_CHECK_LOC_LINK | \
+               SK_RLMT_CHECK_REM_LINK | SK_RLMT_CHECK_SEG)
+#endif /* RLMT_CHECK_REMOTE */
+
+/* ----- RLMT lookahead result bits ----- */
+
+#define SK_RLMT_RX_RLMT                        1       /* Give packet to RLMT. */
+#define SK_RLMT_RX_PROTOCOL            2       /* Give packet to protocol. */
+
+/* Macros */
+
+#if 0
+SK_AC          *pAC            /* adapter context */
+SK_U32         PortNum         /* receiving port */
+unsigned       PktLen          /* received packet's length */
+SK_BOOL                IsBc            /* Flag: packet is broadcast */
+unsigned       *pOffset        /* offs. of bytes to present to SK_RLMT_LOOKAHEAD */
+unsigned       *pNumBytes      /* #Bytes to present to SK_RLMT_LOOKAHEAD */
+#endif /* 0 */
+
+#define SK_RLMT_PRE_LOOKAHEAD(pAC,PortNum,PktLen,IsBc,pOffset,pNumBytes) { \
+       SK_AC   *_pAC; \
+       SK_U32  _PortNum; \
+       _pAC = (pAC); \
+       _PortNum = (SK_U32)(PortNum); \
+       /* _pAC->Rlmt.Port[_PortNum].PacketsRx++; */ \
+       _pAC->Rlmt.Port[_PortNum].PacketsPerTimeSlot++; \
+    if (_pAC->Rlmt.RlmtOff) { \
+               *(pNumBytes) = 0; \
+    } \
+    else {\
+        if ((_pAC->Rlmt.Port[_PortNum].Net->RlmtMode & SK_RLMT_TRANSPARENT) != 0) { \
+               *(pNumBytes) = 0; \
+       } \
+       else if (IsBc) { \
+               if (_pAC->Rlmt.Port[_PortNum].Net->RlmtMode != SK_RLMT_MODE_CLS) { \
+                       *(pNumBytes) = 6; \
+                       *(pOffset) = 6; \
+               } \
+               else { \
+                       *(pNumBytes) = 0; \
+               } \
+       } \
+       else { \
+               if ((PktLen) > SK_RLMT_MAX_TX_BUF_SIZE) { \
+                       /* _pAC->Rlmt.Port[_PortNum].DataPacketsPerTimeSlot++; */ \
+                       *(pNumBytes) = 0; \
+               } \
+               else { \
+                       *(pNumBytes) = 6; \
+                       *(pOffset) = 0; \
+               } \
+       } \
+    } \
+}
+
+#if 0
+SK_AC          *pAC            /* adapter context */
+SK_U32         PortNum         /* receiving port */
+SK_U8          *pLaPacket,     /* received packet's data (points to pOffset) */
+SK_BOOL                IsBc            /* Flag: packet is broadcast */
+SK_BOOL                IsMc            /* Flag: packet is multicast */
+unsigned       *pForRlmt       /* Result: bits SK_RLMT_RX_RLMT, SK_RLMT_RX_PROTOCOL */
+SK_RLMT_LOOKAHEAD() expects *pNumBytes from
+packet offset *pOffset (s.a.) at *pLaPacket.
+
+If you use SK_RLMT_LOOKAHEAD in a path where you already know if the packet is
+BC, MC, or UC, you should use constants for IsBc and IsMc, so that your compiler
+can trash unneeded parts of the if construction.
+#endif /* 0 */
+
+#define SK_RLMT_LOOKAHEAD(pAC,PortNum,pLaPacket,IsBc,IsMc,pForRlmt) { \
+       SK_AC   *_pAC; \
+       SK_U32  _PortNum; \
+       SK_U8   *_pLaPacket; \
+       _pAC = (pAC); \
+       _PortNum = (SK_U32)(PortNum); \
+       _pLaPacket = (SK_U8 *)(pLaPacket); \
+       if (IsBc) {\
+               if (!SK_ADDR_EQUAL(_pLaPacket, _pAC->Addr.Net[_pAC->Rlmt.Port[ \
+                       _PortNum].Net->NetNumber].CurrentMacAddress.a)) { \
+                       _pAC->Rlmt.Port[_PortNum].BcTimeStamp = SkOsGetTime(_pAC); \
+                       _pAC->Rlmt.CheckSwitch = SK_TRUE; \
+               } \
+               /* _pAC->Rlmt.Port[_PortNum].DataPacketsPerTimeSlot++; */ \
+               *(pForRlmt) = SK_RLMT_RX_PROTOCOL; \
+       } \
+       else if (IsMc) { \
+               if (SK_ADDR_EQUAL(_pLaPacket, BridgeMcAddr.a)) { \
+                       _pAC->Rlmt.Port[_PortNum].BpduPacketsPerTimeSlot++; \
+                       if (_pAC->Rlmt.Port[_PortNum].Net->RlmtMode & SK_RLMT_CHECK_SEG) { \
+                               *(pForRlmt) = SK_RLMT_RX_RLMT | SK_RLMT_RX_PROTOCOL; \
+                       } \
+                       else { \
+                               *(pForRlmt) = SK_RLMT_RX_PROTOCOL; \
+                       } \
+               } \
+               else if (SK_ADDR_EQUAL(_pLaPacket, SkRlmtMcAddr.a)) { \
+                       *(pForRlmt) = SK_RLMT_RX_RLMT; \
+               } \
+               else { \
+                       /* _pAC->Rlmt.Port[_PortNum].DataPacketsPerTimeSlot++; */ \
+                       *(pForRlmt) = SK_RLMT_RX_PROTOCOL; \
+               } \
+       } \
+       else { \
+               if (SK_ADDR_EQUAL( \
+                       _pLaPacket, \
+                       _pAC->Addr.Port[_PortNum].CurrentMacAddress.a)) { \
+                       *(pForRlmt) = SK_RLMT_RX_RLMT; \
+               } \
+               else { \
+                       /* _pAC->Rlmt.Port[_PortNum].DataPacketsPerTimeSlot++; */ \
+                       *(pForRlmt) = SK_RLMT_RX_PROTOCOL; \
+               } \
+       } \
+}
+
+#ifdef SK_RLMT_FAST_LOOKAHEAD
+Error: SK_RLMT_FAST_LOOKAHEAD no longer used. Use new macros for lookahead.
+#endif /* SK_RLMT_FAST_LOOKAHEAD */
+#ifdef SK_RLMT_SLOW_LOOKAHEAD
+Error: SK_RLMT_SLOW_LOOKAHEAD no longer used. Use new macros for lookahead.
+#endif /* SK_RLMT_SLOW_LOOKAHEAD */
+
+/* typedefs *******************************************************************/
+
+#ifdef SK_RLMT_MBUF_PRIVATE
+typedef struct s_RlmtMbuf {
+       some content
+} SK_RLMT_MBUF;
+#endif /* SK_RLMT_MBUF_PRIVATE */
+
+
+#ifdef SK_LA_INFO
+typedef struct s_Rlmt_PacketInfo {
+       unsigned        PacketLength;                   /* Length of packet. */
+       unsigned        PacketType;                             /* Directed/Multicast/Broadcast. */
+} SK_RLMT_PINFO;
+#endif /* SK_LA_INFO */
+
+
+typedef struct s_RootId {
+       SK_U8           Id[8];                                  /* Root Bridge Id. */
+} SK_RLMT_ROOT_ID;
+
+
+typedef struct s_port {
+       SK_MAC_ADDR     CheckAddr;
+       SK_BOOL         SuspectTx;
+} SK_PORT_CHECK;
+
+
+typedef struct s_RlmtNet SK_RLMT_NET;
+
+
+typedef struct s_RlmtPort {
+
+/* ----- Public part (read-only) ----- */
+
+       SK_U8                   PortState;                              /* Current state of this port. */
+
+       /* For PNMI */
+       SK_BOOL                 LinkDown;
+       SK_BOOL                 PortDown;
+       SK_U8                   Align01;
+
+       SK_U32                  PortNumber;                             /* Number of port on adapter. */
+       SK_RLMT_NET *   Net;                                    /* Net port belongs to. */
+
+       SK_U64                  TxHelloCts;
+       SK_U64                  RxHelloCts;
+       SK_U64                  TxSpHelloReqCts;
+       SK_U64                  RxSpHelloCts;
+
+/* ----- Private part ----- */
+
+/*     SK_U64                  PacketsRx; */                           /* Total packets received. */
+       SK_U32                  PacketsPerTimeSlot;             /* Packets rxed between TOs. */
+/*     SK_U32                  DataPacketsPerTimeSlot; */      /* Data packets ... */
+       SK_U32                  BpduPacketsPerTimeSlot; /* BPDU packets rxed in TS. */
+       SK_U64                  BcTimeStamp;                    /* Time of last BC receive. */
+       SK_U64                  GuTimeStamp;                    /* Time of entering GOING_UP. */
+
+       SK_TIMER                UpTimer;                                /* Timer struct Link/Port up. */
+       SK_TIMER                DownRxTimer;                    /* Timer struct down rx. */
+       SK_TIMER                DownTxTimer;                    /* Timer struct down tx. */
+
+       SK_U32                  CheckingState;                  /* Checking State. */
+
+       SK_ADDR_PORT *  AddrPort;
+
+       SK_U8                   Random[4];                              /* Random value. */
+       unsigned                PortsChecked;                   /* #ports checked. */
+       unsigned                PortsSuspect;                   /* #ports checked that are s. */
+       SK_PORT_CHECK   PortCheck[1];
+/*     SK_PORT_CHECK   PortCheck[SK_MAX_MACS - 1]; */
+
+       SK_BOOL                 PortStarted;                    /* Port is started. */
+       SK_BOOL                 PortNoRx;                               /* NoRx for >= 1 time slot. */
+       SK_BOOL                 RootIdSet;
+       SK_RLMT_ROOT_ID Root;                                   /* Root Bridge Id. */
+} SK_RLMT_PORT;
+
+
+struct s_RlmtNet {
+
+/* ----- Public part (read-only) ----- */
+
+       SK_U32                  NetNumber;                      /* Number of net. */
+
+       SK_RLMT_PORT *  Port[SK_MAX_MACS];      /* Ports that belong to this net. */
+       SK_U32                  NumPorts;                       /* Number of ports. */
+       SK_U32                  PrefPort;                       /* Preferred port. */
+
+       /* For PNMI */
+
+       SK_U32                  ChgBcPrio;                      /* Change Priority of last broadcast received */
+       SK_U32                  RlmtMode;                       /* Check ... */
+       SK_U32                  ActivePort;                     /* Active port. */
+       SK_U32                  Preference;             /* 0xFFFFFFFF: Automatic. */
+
+       SK_U8                   RlmtState;                      /* Current RLMT state. */
+
+/* ----- Private part ----- */
+       SK_BOOL                 RootIdSet;
+       SK_U16                  Align01;
+
+       int                             LinksUp;                        /* #Links up. */
+       int                             PortsUp;                        /* #Ports up. */
+       SK_U32                  TimeoutValue;           /* RLMT timeout value. */
+
+       SK_U32                  CheckingState;          /* Checking State. */
+       SK_RLMT_ROOT_ID Root;                           /* Root Bridge Id. */
+
+       SK_TIMER                LocTimer;                       /* Timer struct. */
+       SK_TIMER                SegTimer;                       /* Timer struct. */
+};
+
+
+typedef struct s_Rlmt {
+
+/* ----- Public part (read-only) ----- */
+
+       SK_U32                  NumNets;                        /* Number of nets. */
+       SK_U32                  NetsStarted;            /* Number of nets started. */
+       SK_RLMT_NET             Net[SK_MAX_NETS];       /* Array of available nets. */
+       SK_RLMT_PORT    Port[SK_MAX_MACS];      /* Array of available ports. */
+
+/* ----- Private part ----- */
+       SK_BOOL                 CheckSwitch;
+       SK_BOOL                 RlmtOff;            /* set to zero if the Mac addresses 
+                                           are equal or the second one 
+                                           is zero */
+       SK_U16                  Align01;
+
+} SK_RLMT;
+
+
+extern SK_MAC_ADDR     BridgeMcAddr;
+extern SK_MAC_ADDR     SkRlmtMcAddr;
+
+/* function prototypes ********************************************************/
+
+
+#ifndef SK_KR_PROTO
+
+/* Functions provided by SkRlmt */
+
+/* ANSI/C++ compliant function prototypes */
+
+extern void    SkRlmtInit(
+       SK_AC   *pAC,
+       SK_IOC  IoC,
+       int             Level);
+
+extern int     SkRlmtEvent(
+       SK_AC           *pAC,
+       SK_IOC          IoC,
+       SK_U32          Event,
+       SK_EVPARA       Para);
+
+#else  /* defined(SK_KR_PROTO) */
+
+/* Non-ANSI/C++ compliant function prototypes */
+
+#error KR-style function prototypes are not yet provided.
+
+#endif /* defined(SK_KR_PROTO)) */
+
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __INC_SKRLMT_H */
diff --git a/drivers/net/sk98lin/h/sktimer.h b/drivers/net/sk98lin/h/sktimer.h
new file mode 100644 (file)
index 0000000..04e6d7c
--- /dev/null
@@ -0,0 +1,63 @@
+/******************************************************************************
+ *
+ * Name:       sktimer.h
+ * Project:    Gigabit Ethernet Adapters, Event Scheduler Module
+ * Version:    $Revision: 1.11 $
+ * Date:       $Date: 2003/09/16 12:58:18 $
+ * Purpose:    Defines for the timer functions
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *     (C)Copyright 1998-2002 SysKonnect GmbH.
+ *     (C)Copyright 2002-2003 Marvell.
+ *
+ *     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.
+ *
+ *     The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/*
+ * SKTIMER.H   contains all defines and types for the timer functions
+ */
+
+#ifndef        _SKTIMER_H_
+#define _SKTIMER_H_
+
+#include "h/skqueue.h"
+
+/*
+ * SK timer
+ * - needed wherever a timer is used. Put this in your data structure
+ *   wherever you want.
+ */
+typedef        struct s_Timer SK_TIMER;
+
+struct s_Timer {
+       SK_TIMER        *TmNext;        /* linked list */
+       SK_U32          TmClass;        /* Timer Event class */
+       SK_U32          TmEvent;        /* Timer Event value */
+       SK_EVPARA       TmPara;         /* Timer Event parameter */
+       SK_U32          TmDelta;        /* delta time */
+       int                     TmActive;       /* flag: active/inactive */
+};
+
+/*
+ * Timer control struct.
+ * - use in Adapters context name pAC->Tim
+ */
+typedef        struct s_TimCtrl {
+       SK_TIMER        *StQueue;       /* Head of Timer queue */
+} SK_TIMCTRL;
+
+extern void SkTimerInit(SK_AC *pAC, SK_IOC Ioc, int Level);
+extern void SkTimerStop(SK_AC *pAC, SK_IOC Ioc, SK_TIMER *pTimer);
+extern void SkTimerStart(SK_AC *pAC, SK_IOC Ioc, SK_TIMER *pTimer,
+       SK_U32 Time, SK_U32 Class, SK_U32 Event, SK_EVPARA Para);
+extern void SkTimerDone(SK_AC *pAC, SK_IOC Ioc);
+#endif /* _SKTIMER_H_ */
diff --git a/drivers/net/sk98lin/h/sktypes.h b/drivers/net/sk98lin/h/sktypes.h
new file mode 100644 (file)
index 0000000..40edc96
--- /dev/null
@@ -0,0 +1,69 @@
+/******************************************************************************
+ *
+ * Name:       sktypes.h
+ * Project:    GEnesis, PCI Gigabit Ethernet Adapter
+ * Version:    $Revision: 1.2 $
+ * Date:       $Date: 2003/10/07 08:16:51 $
+ * Purpose:    Define data types for Linux
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *     (C)Copyright 1998-2002 SysKonnect GmbH.
+ *     (C)Copyright 2002-2003 Marvell.
+ *
+ *     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.
+ *
+ *     The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+/******************************************************************************
+ *
+ * Description:
+ *
+ * In this file, all data types that are needed by the common modules
+ * are mapped to Linux data types.
+ * 
+ *
+ * Include File Hierarchy:
+ *
+ *
+ ******************************************************************************/
+
+#ifndef __INC_SKTYPES_H
+#define __INC_SKTYPES_H
+
+
+/* defines *******************************************************************/
+
+/*
+ * Data types with a specific size. 'I' = signed, 'U' = unsigned.
+ */
+#define SK_I8  s8
+#define SK_U8  u8
+#define SK_I16 s16
+#define SK_U16 u16
+#define SK_I32 s32
+#define SK_U32 u32
+#define SK_I64 s64
+#define SK_U64 u64
+
+#define SK_UPTR        ulong           /* casting pointer <-> integral */
+
+/*
+* Boolean type.
+*/
+#define SK_BOOL                SK_U8
+#define SK_FALSE       0
+#define SK_TRUE                (!SK_FALSE)
+
+/* typedefs *******************************************************************/
+
+/* function prototypes ********************************************************/
+
+#endif /* __INC_SKTYPES_H */
diff --git a/drivers/net/sk98lin/h/skversion.h b/drivers/net/sk98lin/h/skversion.h
new file mode 100644 (file)
index 0000000..a1a7294
--- /dev/null
@@ -0,0 +1,38 @@
+/******************************************************************************
+ *
+ * Name:       version.h
+ * Project:    GEnesis, PCI Gigabit Ethernet Adapter
+ * Version:    $Revision: 1.5 $
+ * Date:       $Date: 2003/10/07 08:16:51 $
+ * Purpose:    SK specific Error log support
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *     (C)Copyright 1998-2002 SysKonnect GmbH.
+ *     (C)Copyright 2002-2003 Marvell.
+ *
+ *     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.
+ *
+ *     The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+#ifdef lint
+static const char SysKonnectFileId[] = "@(#) (C) SysKonnect GmbH.";
+static const char SysKonnectBuildNumber[] =
+       "@(#)SK-BUILD: 6.23 PL: 01"; 
+#endif /* !defined(lint) */
+
+#define BOOT_STRING    "sk98lin: Network Device Driver v6.23\n" \
+                       "(C)Copyright 1999-2004 Marvell(R)."
+
+#define VER_STRING     "6.23"
+#define DRIVER_FILE_NAME       "sk98lin"
+#define DRIVER_REL_DATE                "Feb-13-2004"
+
+
diff --git a/drivers/net/sk98lin/h/skvpd.h b/drivers/net/sk98lin/h/skvpd.h
new file mode 100644 (file)
index 0000000..fdd9e48
--- /dev/null
@@ -0,0 +1,248 @@
+/******************************************************************************
+ *
+ * Name:       skvpd.h
+ * Project:    GEnesis, PCI Gigabit Ethernet Adapter
+ * Version:    $Revision: 1.15 $
+ * Date:       $Date: 2003/01/13 10:39:38 $
+ * Purpose:    Defines and Macros for VPD handling
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *     (C)Copyright 1998-2003 SysKonnect GmbH.
+ *
+ *     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.
+ *
+ *     The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/*
+ * skvpd.h     contains Diagnostic specific defines for VPD handling
+ */
+
+#ifndef __INC_SKVPD_H_
+#define __INC_SKVPD_H_
+
+/*
+ * Define Resource Type Identifiers and VPD keywords
+ */
+#define        RES_ID          0x82    /* Resource Type ID String (Product Name) */
+#define RES_VPD_R      0x90    /* start of VPD read only area */
+#define RES_VPD_W      0x91    /* start of VPD read/write area */
+#define RES_END                0x78    /* Resource Type End Tag */
+
+#ifndef VPD_NAME
+#define VPD_NAME       "Name"  /* Product Name, VPD name of RES_ID */
+#endif /* VPD_NAME */
+#define VPD_PN         "PN"    /* Adapter Part Number */
+#define        VPD_EC          "EC"    /* Adapter Engineering Level */
+#define VPD_MN         "MN"    /* Manufacture ID */
+#define VPD_SN         "SN"    /* Serial Number */
+#define VPD_CP         "CP"    /* Extended Capability */
+#define VPD_RV         "RV"    /* Checksum and Reserved */
+#define        VPD_YA          "YA"    /* Asset Tag Identifier */
+#define VPD_VL         "VL"    /* First Error Log Message (SK specific) */
+#define VPD_VF         "VF"    /* Second Error Log Message (SK specific) */
+#define VPD_RW         "RW"    /* Remaining Read / Write Area */
+
+/* 'type' values for vpd_setup_para() */
+#define VPD_RO_KEY     1       /* RO keys are "PN", "EC", "MN", "SN", "RV" */
+#define VPD_RW_KEY     2       /* RW keys are "Yx", "Vx", and "RW" */
+
+/* 'op' values for vpd_setup_para() */
+#define        ADD_KEY         1       /* add the key at the pos "RV" or "RW" */
+#define OWR_KEY                2       /* overwrite key if already exists */
+
+/*
+ * Define READ and WRITE Constants.
+ */
+
+#define VPD_DEV_ID_GENESIS     0x4300
+
+#define        VPD_SIZE_YUKON          256
+#define        VPD_SIZE_GENESIS        512
+#define        VPD_SIZE                        512
+#define VPD_READ       0x0000
+#define VPD_WRITE      0x8000
+
+#define VPD_STOP(pAC,IoC)      VPD_OUT16(pAC,IoC,PCI_VPD_ADR_REG,VPD_WRITE)
+
+#define VPD_GET_RES_LEN(p)     ((unsigned int) \
+                                       (* (SK_U8 *)&(p)[1]) |\
+                                       ((* (SK_U8 *)&(p)[2]) << 8))
+#define VPD_GET_VPD_LEN(p)     ((unsigned int)(* (SK_U8 *)&(p)[2]))
+#define VPD_GET_VAL(p)         ((char *)&(p)[3])
+
+#define VPD_MAX_LEN    50
+
+/* VPD status */
+       /* bit 7..1 reserved */
+#define VPD_VALID      (1<<0)  /* VPD data buffer, vpd_free_ro, */
+                                                       /* and vpd_free_rw valid         */
+
+/*
+ * VPD structs
+ */
+typedef        struct s_vpd_status {
+       unsigned short  Align01;                        /* Alignment */
+       unsigned short  vpd_status;                     /* VPD status, description see above */
+       int                             vpd_free_ro;            /* unused bytes in read only area */
+       int                             vpd_free_rw;            /* bytes available in read/write area */
+} SK_VPD_STATUS;
+
+typedef        struct s_vpd {
+       SK_VPD_STATUS   v;                                      /* VPD status structure */
+       char                    vpd_buf[VPD_SIZE];      /* VPD buffer */
+       int                             rom_size;                       /* VPD ROM Size from PCI_OUR_REG_2 */
+       int                             vpd_size;                       /* saved VPD-size */
+} SK_VPD;
+
+typedef        struct s_vpd_para {
+       unsigned int    p_len;  /* parameter length */
+       char                    *p_val; /* points to the value */
+} SK_VPD_PARA;
+
+/*
+ * structure of Large Resource Type Identifiers
+ */
+
+/* was removed because of alignment problems */
+
+/*
+ * structure of VPD keywords
+ */
+typedef        struct s_vpd_key {
+       char                    p_key[2];       /* 2 bytes ID string */
+       unsigned char   p_len;          /* 1 byte length */
+       char                    p_val;          /* start of the value string */
+} SK_VPD_KEY;
+
+
+/*
+ * System specific VPD macros
+ */
+#ifndef SKDIAG
+#ifndef VPD_DO_IO
+#define VPD_OUT8(pAC,IoC,Addr,Val)     (void)SkPciWriteCfgByte(pAC,Addr,Val)
+#define VPD_OUT16(pAC,IoC,Addr,Val)    (void)SkPciWriteCfgWord(pAC,Addr,Val)
+#define VPD_IN8(pAC,IoC,Addr,pVal)     (void)SkPciReadCfgByte(pAC,Addr,pVal)
+#define VPD_IN16(pAC,IoC,Addr,pVal)    (void)SkPciReadCfgWord(pAC,Addr,pVal)
+#define VPD_IN32(pAC,IoC,Addr,pVal)    (void)SkPciReadCfgDWord(pAC,Addr,pVal)
+#else  /* VPD_DO_IO */
+#define VPD_OUT8(pAC,IoC,Addr,Val)     SK_OUT8(IoC,PCI_C(Addr),Val)
+#define VPD_OUT16(pAC,IoC,Addr,Val)    SK_OUT16(IoC,PCI_C(Addr),Val)
+#define VPD_IN8(pAC,IoC,Addr,pVal)     SK_IN8(IoC,PCI_C(Addr),pVal)
+#define VPD_IN16(pAC,IoC,Addr,pVal)    SK_IN16(IoC,PCI_C(Addr),pVal)
+#define VPD_IN32(pAC,IoC,Addr,pVal)    SK_IN32(IoC,PCI_C(Addr),pVal)
+#endif /* VPD_DO_IO */
+#else  /* SKDIAG */
+#define VPD_OUT8(pAC,Ioc,Addr,Val) {                   \
+               if ((pAC)->DgT.DgUseCfgCycle)                   \
+                       SkPciWriteCfgByte(pAC,Addr,Val);        \
+               else                                                                    \
+                       SK_OUT8(pAC,PCI_C(Addr),Val);           \
+               }
+#define VPD_OUT16(pAC,Ioc,Addr,Val) {                  \
+               if ((pAC)->DgT.DgUseCfgCycle)                   \
+                       SkPciWriteCfgWord(pAC,Addr,Val);        \
+               else                                            \
+                       SK_OUT16(pAC,PCI_C(Addr),Val);          \
+               }
+#define VPD_IN8(pAC,Ioc,Addr,pVal) {                   \
+               if ((pAC)->DgT.DgUseCfgCycle)                   \
+                       SkPciReadCfgByte(pAC,Addr,pVal);        \
+               else                                            \
+                       SK_IN8(pAC,PCI_C(Addr),pVal);           \
+               }
+#define VPD_IN16(pAC,Ioc,Addr,pVal) {                  \
+               if ((pAC)->DgT.DgUseCfgCycle)                   \
+                       SkPciReadCfgWord(pAC,Addr,pVal);        \
+               else                                            \
+                       SK_IN16(pAC,PCI_C(Addr),pVal);          \
+               }
+#define VPD_IN32(pAC,Ioc,Addr,pVal) {                  \
+               if ((pAC)->DgT.DgUseCfgCycle)                   \
+                       SkPciReadCfgDWord(pAC,Addr,pVal);       \
+               else                                            \
+                       SK_IN32(pAC,PCI_C(Addr),pVal);          \
+               }
+#endif /* nSKDIAG */
+
+/* function prototypes ********************************************************/
+
+#ifndef        SK_KR_PROTO
+#ifdef SKDIAG
+extern SK_U32  VpdReadDWord(
+       SK_AC           *pAC,
+       SK_IOC          IoC,
+       int                     addr);
+#endif /* SKDIAG */
+
+extern SK_VPD_STATUS   *VpdStat(
+       SK_AC           *pAC,
+       SK_IOC          IoC);
+
+extern int     VpdKeys(
+       SK_AC           *pAC,
+       SK_IOC          IoC,
+       char            *buf,
+       int                     *len,
+       int                     *elements);
+
+extern int     VpdRead(
+       SK_AC           *pAC,
+       SK_IOC          IoC,
+       const char      *key,
+       char            *buf,
+       int                     *len);
+
+extern SK_BOOL VpdMayWrite(
+       char            *key);
+
+extern int     VpdWrite(
+       SK_AC           *pAC,
+       SK_IOC          IoC,
+       const char      *key,
+       const char      *buf);
+
+extern int     VpdDelete(
+       SK_AC           *pAC,
+       SK_IOC          IoC,
+       char            *key);
+
+extern int     VpdUpdate(
+       SK_AC           *pAC,
+       SK_IOC          IoC);
+
+#ifdef SKDIAG
+extern int     VpdReadBlock(
+       SK_AC           *pAC,
+       SK_IOC          IoC,
+       char            *buf,
+       int                     addr,
+       int                     len);
+
+extern int     VpdWriteBlock(
+       SK_AC           *pAC,
+       SK_IOC          IoC,
+       char            *buf,
+       int                     addr,
+       int                     len);
+#endif /* SKDIAG */
+#else  /* SK_KR_PROTO */
+extern SK_U32  VpdReadDWord();
+extern SK_VPD_STATUS   *VpdStat();
+extern int     VpdKeys();
+extern int     VpdRead();
+extern SK_BOOL VpdMayWrite();
+extern int     VpdWrite();
+extern int     VpdDelete();
+extern int     VpdUpdate();
+#endif /* SK_KR_PROTO */
+
+#endif /* __INC_SKVPD_H_ */
diff --git a/drivers/net/sk98lin/h/xmac_ii.h b/drivers/net/sk98lin/h/xmac_ii.h
new file mode 100644 (file)
index 0000000..7f8e6d0
--- /dev/null
@@ -0,0 +1,1579 @@
+/******************************************************************************
+ *
+ * Name:       xmac_ii.h
+ * Project:    Gigabit Ethernet Adapters, Common Modules
+ * Version:    $Revision: 1.52 $
+ * Date:       $Date: 2003/10/02 16:35:50 $
+ * Purpose:    Defines and Macros for Gigabit Ethernet Controller
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *     (C)Copyright 1998-2002 SysKonnect.
+ *     (C)Copyright 2002-2003 Marvell.
+ *
+ *     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.
+ *
+ *     The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+#ifndef __INC_XMAC_H
+#define __INC_XMAC_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/* defines ********************************************************************/
+
+/*
+ * XMAC II registers
+ *
+ * The XMAC registers are 16 or 32 bits wide.
+ * The XMACs host processor interface is set to 16 bit mode,
+ * therefore ALL registers will be addressed with 16 bit accesses.
+ *
+ * The following macros are provided to access the XMAC registers
+ * XM_IN16(), XM_OUT16, XM_IN32(), XM_OUT32(), XM_INADR(), XM_OUTADR(),
+ * XM_INHASH(), and XM_OUTHASH().
+ * The macros are defined in SkGeHw.h.
+ *
+ * Note:       NA reg  = Network Address e.g DA, SA etc.
+ *
+ */
+#define XM_MMU_CMD             0x0000  /* 16 bit r/w   MMU Command Register */
+       /* 0x0004:              reserved */
+#define XM_POFF                        0x0008  /* 32 bit r/w   Packet Offset Register */
+#define XM_BURST               0x000c  /* 32 bit r/w   Burst Register for half duplex*/
+#define XM_1L_VLAN_TAG 0x0010  /* 16 bit r/w   One Level VLAN Tag ID */
+#define XM_2L_VLAN_TAG 0x0014  /* 16 bit r/w   Two Level VLAN Tag ID */
+       /* 0x0018 - 0x001e:     reserved */
+#define XM_TX_CMD              0x0020  /* 16 bit r/w   Transmit Command Register */
+#define XM_TX_RT_LIM   0x0024  /* 16 bit r/w   Transmit Retry Limit Register */
+#define XM_TX_STIME            0x0028  /* 16 bit r/w   Transmit Slottime Register */
+#define XM_TX_IPG              0x002c  /* 16 bit r/w   Transmit Inter Packet Gap */
+#define XM_RX_CMD              0x0030  /* 16 bit r/w   Receive Command Register */
+#define XM_PHY_ADDR            0x0034  /* 16 bit r/w   PHY Address Register */
+#define XM_PHY_DATA            0x0038  /* 16 bit r/w   PHY Data Register */
+       /* 0x003c:              reserved */
+#define XM_GP_PORT             0x0040  /* 32 bit r/w   General Purpose Port Register */
+#define XM_IMSK                        0x0044  /* 16 bit r/w   Interrupt Mask Register */
+#define XM_ISRC                        0x0048  /* 16 bit r/o   Interrupt Status Register */
+#define XM_HW_CFG              0x004c  /* 16 bit r/w   Hardware Config Register */
+       /* 0x0050 - 0x005e:     reserved */
+#define XM_TX_LO_WM            0x0060  /* 16 bit r/w   Tx FIFO Low Water Mark */
+#define XM_TX_HI_WM            0x0062  /* 16 bit r/w   Tx FIFO High Water Mark */
+#define XM_TX_THR              0x0064  /* 16 bit r/w   Tx Request Threshold */
+#define XM_HT_THR              0x0066  /* 16 bit r/w   Host Request Threshold */
+#define XM_PAUSE_DA            0x0068  /* NA reg r/w   Pause Destination Address */
+       /* 0x006e:              reserved */
+#define XM_CTL_PARA            0x0070  /* 32 bit r/w   Control Parameter Register */
+#define XM_MAC_OPCODE  0x0074  /* 16 bit r/w   Opcode for MAC control frames */
+#define XM_MAC_PTIME   0x0076  /* 16 bit r/w   Pause time for MAC ctrl frames*/
+#define XM_TX_STAT             0x0078  /* 32 bit r/o   Tx Status LIFO Register */
+
+       /* 0x0080 - 0x00fc:     16 NA reg r/w   Exact Match Address Registers */
+       /*                              use the XM_EXM() macro to address */
+#define XM_EXM_START   0x0080  /* r/w  Start Address of the EXM Regs */
+
+       /*
+        * XM_EXM(Reg)
+        *
+        * returns the XMAC address offset of specified Exact Match Addr Reg
+        *
+        * para:        Reg     EXM register to addr    (0 .. 15)
+        *
+        * usage:       XM_INADDR(IoC, MAC_1, XM_EXM(i), &val[i]);
+        */
+#define XM_EXM(Reg)    (XM_EXM_START + ((Reg) << 3))
+
+#define XM_SRC_CHK             0x0100  /* NA reg r/w   Source Check Address Register */
+#define XM_SA                  0x0108  /* NA reg r/w   Station Address Register */
+#define XM_HSM                 0x0110  /* 64 bit r/w   Hash Match Address Registers */
+#define XM_RX_LO_WM            0x0118  /* 16 bit r/w   Receive Low Water Mark */
+#define XM_RX_HI_WM            0x011a  /* 16 bit r/w   Receive High Water Mark */
+#define XM_RX_THR              0x011c  /* 32 bit r/w   Receive Request Threshold */
+#define XM_DEV_ID              0x0120  /* 32 bit r/o   Device ID Register */
+#define XM_MODE                        0x0124  /* 32 bit r/w   Mode Register */
+#define XM_LSA                 0x0128  /* NA reg r/o   Last Source Register */
+       /* 0x012e:              reserved */
+#define XM_TS_READ             0x0130  /* 32 bit r/o   Time Stamp Read Register */
+#define XM_TS_LOAD             0x0134  /* 32 bit r/o   Time Stamp Load Value */
+       /* 0x0138 - 0x01fe:     reserved */
+#define XM_STAT_CMD    0x0200  /* 16 bit r/w   Statistics Command Register */
+#define XM_RX_CNT_EV   0x0204  /* 32 bit r/o   Rx Counter Event Register */
+#define XM_TX_CNT_EV   0x0208  /* 32 bit r/o   Tx Counter Event Register */
+#define XM_RX_EV_MSK   0x020c  /* 32 bit r/w   Rx Counter Event Mask */
+#define XM_TX_EV_MSK   0x0210  /* 32 bit r/w   Tx Counter Event Mask */
+       /* 0x0204 - 0x027e:     reserved */
+#define XM_TXF_OK              0x0280  /* 32 bit r/o   Frames Transmitted OK Conuter */
+#define XM_TXO_OK_HI   0x0284  /* 32 bit r/o   Octets Transmitted OK High Cnt*/
+#define XM_TXO_OK_LO   0x0288  /* 32 bit r/o   Octets Transmitted OK Low Cnt */
+#define XM_TXF_BC_OK   0x028c  /* 32 bit r/o   Broadcast Frames Xmitted OK */
+#define XM_TXF_MC_OK   0x0290  /* 32 bit r/o   Multicast Frames Xmitted OK */
+#define XM_TXF_UC_OK   0x0294  /* 32 bit r/o   Unicast Frames Xmitted OK */
+#define XM_TXF_LONG            0x0298  /* 32 bit r/o   Tx Long Frame Counter */
+#define XM_TXE_BURST   0x029c  /* 32 bit r/o   Tx Burst Event Counter */
+#define XM_TXF_MPAUSE  0x02a0  /* 32 bit r/o   Tx Pause MAC Ctrl Frame Cnt */
+#define XM_TXF_MCTRL   0x02a4  /* 32 bit r/o   Tx MAC Ctrl Frame Counter */
+#define XM_TXF_SNG_COL 0x02a8  /* 32 bit r/o   Tx Single Collision Counter */
+#define XM_TXF_MUL_COL 0x02ac  /* 32 bit r/o   Tx Multiple Collision Counter */
+#define XM_TXF_ABO_COL 0x02b0  /* 32 bit r/o   Tx aborted due to Exces. Col. */
+#define XM_TXF_LAT_COL 0x02b4  /* 32 bit r/o   Tx Late Collision Counter */
+#define XM_TXF_DEF             0x02b8  /* 32 bit r/o   Tx Deferred Frame Counter */
+#define XM_TXF_EX_DEF  0x02bc  /* 32 bit r/o   Tx Excessive Deferall Counter */
+#define XM_TXE_FIFO_UR 0x02c0  /* 32 bit r/o   Tx FIFO Underrun Event Cnt */
+#define XM_TXE_CS_ERR  0x02c4  /* 32 bit r/o   Tx Carrier Sense Error Cnt */
+#define XM_TXP_UTIL            0x02c8  /* 32 bit r/o   Tx Utilization in % */
+       /* 0x02cc - 0x02ce:     reserved */
+#define XM_TXF_64B             0x02d0  /* 32 bit r/o   64 Byte Tx Frame Counter */
+#define XM_TXF_127B            0x02d4  /* 32 bit r/o   65-127 Byte Tx Frame Counter */
+#define XM_TXF_255B            0x02d8  /* 32 bit r/o   128-255 Byte Tx Frame Counter */
+#define XM_TXF_511B            0x02dc  /* 32 bit r/o   256-511 Byte Tx Frame Counter */
+#define XM_TXF_1023B   0x02e0  /* 32 bit r/o   512-1023 Byte Tx Frame Counter*/
+#define XM_TXF_MAX_SZ  0x02e4  /* 32 bit r/o   1024-MaxSize Byte Tx Frame Cnt*/
+       /* 0x02e8 - 0x02fe:     reserved */
+#define XM_RXF_OK              0x0300  /* 32 bit r/o   Frames Received OK */
+#define XM_RXO_OK_HI   0x0304  /* 32 bit r/o   Octets Received OK High Cnt */
+#define XM_RXO_OK_LO   0x0308  /* 32 bit r/o   Octets Received OK Low Counter*/
+#define XM_RXF_BC_OK   0x030c  /* 32 bit r/o   Broadcast Frames Received OK */
+#define XM_RXF_MC_OK   0x0310  /* 32 bit r/o   Multicast Frames Received OK */
+#define XM_RXF_UC_OK   0x0314  /* 32 bit r/o   Unicast Frames Received OK */
+#define XM_RXF_MPAUSE  0x0318  /* 32 bit r/o   Rx Pause MAC Ctrl Frame Cnt */
+#define XM_RXF_MCTRL   0x031c  /* 32 bit r/o   Rx MAC Ctrl Frame Counter */
+#define XM_RXF_INV_MP  0x0320  /* 32 bit r/o   Rx invalid Pause Frame Cnt */
+#define XM_RXF_INV_MOC 0x0324  /* 32 bit r/o   Rx Frames with inv. MAC Opcode*/
+#define XM_RXE_BURST   0x0328  /* 32 bit r/o   Rx Burst Event Counter */
+#define XM_RXE_FMISS   0x032c  /* 32 bit r/o   Rx Missed Frames Event Cnt */
+#define XM_RXF_FRA_ERR 0x0330  /* 32 bit r/o   Rx Framing Error Counter */
+#define XM_RXE_FIFO_OV 0x0334  /* 32 bit r/o   Rx FIFO overflow Event Cnt */
+#define XM_RXF_JAB_PKT 0x0338  /* 32 bit r/o   Rx Jabber Packet Frame Cnt */
+#define XM_RXE_CAR_ERR 0x033c  /* 32 bit r/o   Rx Carrier Event Error Cnt */
+#define XM_RXF_LEN_ERR 0x0340  /* 32 bit r/o   Rx in Range Length Error */
+#define XM_RXE_SYM_ERR 0x0344  /* 32 bit r/o   Rx Symbol Error Counter */
+#define XM_RXE_SHT_ERR 0x0348  /* 32 bit r/o   Rx Short Event Error Cnt */
+#define XM_RXE_RUNT            0x034c  /* 32 bit r/o   Rx Runt Event Counter */
+#define XM_RXF_LNG_ERR 0x0350  /* 32 bit r/o   Rx Frame too Long Error Cnt */
+#define XM_RXF_FCS_ERR 0x0354  /* 32 bit r/o   Rx Frame Check Seq. Error Cnt */
+       /* 0x0358 - 0x035a:     reserved */
+#define XM_RXF_CEX_ERR 0x035c  /* 32 bit r/o   Rx Carrier Ext Error Frame Cnt*/
+#define XM_RXP_UTIL            0x0360  /* 32 bit r/o   Rx Utilization in % */
+       /* 0x0364 - 0x0366:     reserved */
+#define XM_RXF_64B             0x0368  /* 32 bit r/o   64 Byte Rx Frame Counter */
+#define XM_RXF_127B            0x036c  /* 32 bit r/o   65-127 Byte Rx Frame Counter */
+#define XM_RXF_255B            0x0370  /* 32 bit r/o   128-255 Byte Rx Frame Counter */
+#define XM_RXF_511B            0x0374  /* 32 bit r/o   256-511 Byte Rx Frame Counter */
+#define XM_RXF_1023B   0x0378  /* 32 bit r/o   512-1023 Byte Rx Frame Counter*/
+#define XM_RXF_MAX_SZ  0x037c  /* 32 bit r/o   1024-MaxSize Byte Rx Frame Cnt*/
+       /* 0x02e8 - 0x02fe:     reserved */
+
+
+/*----------------------------------------------------------------------------*/
+/*
+ * XMAC Bit Definitions
+ *
+ * If the bit access behaviour differs from the register access behaviour
+ * (r/w, r/o) this is documented after the bit number.
+ * The following bit access behaviours are used:
+ *     (sc)    self clearing
+ *     (ro)    read only
+ */
+
+/*     XM_MMU_CMD      16 bit r/w      MMU Command Register */
+                                                               /* Bit 15..13:  reserved */
+#define XM_MMU_PHY_RDY (1<<12) /* Bit 12:      PHY Read Ready */
+#define XM_MMU_PHY_BUSY        (1<<11) /* Bit 11:      PHY Busy */
+#define XM_MMU_IGN_PF  (1<<10) /* Bit 10:      Ignore Pause Frame */
+#define XM_MMU_MAC_LB  (1<<9)  /* Bit  9:      Enable MAC Loopback */
+                                                               /* Bit  8:      reserved */
+#define XM_MMU_FRC_COL (1<<7)  /* Bit  7:      Force Collision */
+#define XM_MMU_SIM_COL (1<<6)  /* Bit  6:      Simulate Collision */
+#define XM_MMU_NO_PRE  (1<<5)  /* Bit  5:      No MDIO Preamble */
+#define XM_MMU_GMII_FD (1<<4)  /* Bit  4:      GMII uses Full Duplex */
+#define XM_MMU_RAT_CTRL        (1<<3)  /* Bit  3:      Enable Rate Control */
+#define XM_MMU_GMII_LOOP (1<<2)        /* Bit  2:      PHY is in Loopback Mode */
+#define XM_MMU_ENA_RX  (1<<1)  /* Bit  1:      Enable Receiver */
+#define XM_MMU_ENA_TX  (1<<0)  /* Bit  0:      Enable Transmitter */
+
+
+/*     XM_TX_CMD       16 bit r/w      Transmit Command Register */
+                                                               /* Bit 15..7:   reserved */
+#define XM_TX_BK2BK            (1<<6)  /* Bit  6:      Ignor Carrier Sense (Tx Bk2Bk)*/
+#define XM_TX_ENC_BYP  (1<<5)  /* Bit  5:      Set Encoder in Bypass Mode */
+#define XM_TX_SAM_LINE (1<<4)  /* Bit  4: (sc) Start utilization calculation */
+#define XM_TX_NO_GIG_MD        (1<<3)  /* Bit  3:      Disable Carrier Extension */
+#define XM_TX_NO_PRE   (1<<2)  /* Bit  2:      Disable Preamble Generation */
+#define XM_TX_NO_CRC   (1<<1)  /* Bit  1:      Disable CRC Generation */
+#define XM_TX_AUTO_PAD (1<<0)  /* Bit  0:      Enable Automatic Padding */
+
+
+/*     XM_TX_RT_LIM    16 bit r/w      Transmit Retry Limit Register */
+                                                               /* Bit 15..5:   reserved */
+#define XM_RT_LIM_MSK  0x1f    /* Bit  4..0:   Tx Retry Limit */
+
+
+/*     XM_TX_STIME     16 bit r/w      Transmit Slottime Register */
+                                                               /* Bit 15..7:   reserved */
+#define XM_STIME_MSK   0x7f    /* Bit  6..0:   Tx Slottime bits */
+
+
+/*     XM_TX_IPG       16 bit r/w      Transmit Inter Packet Gap */
+                                                               /* Bit 15..8:   reserved */
+#define XM_IPG_MSK             0xff    /* Bit  7..0:   IPG value bits */
+
+
+/*     XM_RX_CMD       16 bit r/w      Receive Command Register */
+                                                               /* Bit 15..9:   reserved */
+#define XM_RX_LENERR_OK (1<<8) /* Bit  8       don't set Rx Err bit for */
+                                                               /*              inrange error packets */
+#define XM_RX_BIG_PK_OK        (1<<7)  /* Bit  7       don't set Rx Err bit for */
+                                                               /*              jumbo packets */
+#define XM_RX_IPG_CAP  (1<<6)  /* Bit  6       repl. type field with IPG */
+#define XM_RX_TP_MD            (1<<5)  /* Bit  5:      Enable transparent Mode */
+#define XM_RX_STRIP_FCS        (1<<4)  /* Bit  4:      Enable FCS Stripping */
+#define XM_RX_SELF_RX  (1<<3)  /* Bit  3:      Enable Rx of own packets */
+#define XM_RX_SAM_LINE (1<<2)  /* Bit  2: (sc) Start utilization calculation */
+#define XM_RX_STRIP_PAD        (1<<1)  /* Bit  1:      Strip pad bytes of Rx frames */
+#define XM_RX_DIS_CEXT (1<<0)  /* Bit  0:      Disable carrier ext. check */
+
+
+/*     XM_PHY_ADDR     16 bit r/w      PHY Address Register */
+                                                               /* Bit 15..5:   reserved */
+#define XM_PHY_ADDR_SZ 0x1f    /* Bit  4..0:   PHY Address bits */
+
+
+/*     XM_GP_PORT      32 bit r/w      General Purpose Port Register */
+                                                               /* Bit 31..7:   reserved */
+#define XM_GP_ANIP             (1L<<6) /* Bit  6: (ro) Auto-Neg. in progress */
+#define XM_GP_FRC_INT  (1L<<5) /* Bit  5: (sc) Force Interrupt */
+                                                               /* Bit  4:      reserved */
+#define XM_GP_RES_MAC  (1L<<3) /* Bit  3: (sc) Reset MAC and FIFOs */
+#define XM_GP_RES_STAT (1L<<2) /* Bit  2: (sc) Reset the statistics module */
+                                                               /* Bit  1:      reserved */
+#define XM_GP_INP_ASS  (1L<<0) /* Bit  0: (ro) GP Input Pin asserted */
+
+
+/*     XM_IMSK         16 bit r/w      Interrupt Mask Register */
+/*     XM_ISRC         16 bit r/o      Interrupt Status Register */
+                                                               /* Bit 15:      reserved */
+#define XM_IS_LNK_AE   (1<<14) /* Bit 14:      Link Asynchronous Event */
+#define XM_IS_TX_ABORT (1<<13) /* Bit 13:      Transmit Abort, late Col. etc */
+#define XM_IS_FRC_INT  (1<<12) /* Bit 12:      Force INT bit set in GP */
+#define XM_IS_INP_ASS  (1<<11) /* Bit 11:      Input Asserted, GP bit 0 set */
+#define XM_IS_LIPA_RC  (1<<10) /* Bit 10:      Link Partner requests config */
+#define XM_IS_RX_PAGE  (1<<9)  /* Bit  9:      Page Received */
+#define XM_IS_TX_PAGE  (1<<8)  /* Bit  8:      Next Page Loaded for Transmit */
+#define XM_IS_AND              (1<<7)  /* Bit  7:      Auto-Negotiation Done */
+#define XM_IS_TSC_OV   (1<<6)  /* Bit  6:      Time Stamp Counter Overflow */
+#define XM_IS_RXC_OV   (1<<5)  /* Bit  5:      Rx Counter Event Overflow */
+#define XM_IS_TXC_OV   (1<<4)  /* Bit  4:      Tx Counter Event Overflow */
+#define XM_IS_RXF_OV   (1<<3)  /* Bit  3:      Receive FIFO Overflow */
+#define XM_IS_TXF_UR   (1<<2)  /* Bit  2:      Transmit FIFO Underrun */
+#define XM_IS_TX_COMP  (1<<1)  /* Bit  1:      Frame Tx Complete */
+#define XM_IS_RX_COMP  (1<<0)  /* Bit  0:      Frame Rx Complete */
+
+#define XM_DEF_MSK     (~(XM_IS_INP_ASS | XM_IS_LIPA_RC | XM_IS_RX_PAGE |\
+                       XM_IS_AND | XM_IS_RXC_OV | XM_IS_TXC_OV | XM_IS_TXF_UR))
+
+
+/*     XM_HW_CFG       16 bit r/w      Hardware Config Register */
+                                                               /* Bit 15.. 4:  reserved */
+#define XM_HW_GEN_EOP  (1<<3)  /* Bit  3:      generate End of Packet pulse */
+#define XM_HW_COM4SIG  (1<<2)  /* Bit  2:      use Comma Detect for Sig. Det.*/
+                                                               /* Bit  1:      reserved */
+#define XM_HW_GMII_MD  (1<<0)  /* Bit  0:      GMII Interface selected */
+
+
+/*     XM_TX_LO_WM     16 bit r/w      Tx FIFO Low Water Mark */
+/*     XM_TX_HI_WM     16 bit r/w      Tx FIFO High Water Mark */
+                                                               /* Bit 15..10   reserved */
+#define XM_TX_WM_MSK   0x01ff  /* Bit  9.. 0   Tx FIFO Watermark bits */
+
+/*     XM_TX_THR       16 bit r/w      Tx Request Threshold */
+/*     XM_HT_THR       16 bit r/w      Host Request Threshold */
+/*     XM_RX_THR       16 bit r/w      Rx Request Threshold */
+                                                               /* Bit 15..11   reserved */
+#define XM_THR_MSK             0x03ff  /* Bit 10.. 0   Rx/Tx Request Threshold bits */
+
+
+/*     XM_TX_STAT      32 bit r/o      Tx Status LIFO Register */
+#define XM_ST_VALID            (1UL<<31)       /* Bit 31:      Status Valid */
+#define XM_ST_BYTE_CNT (0x3fffL<<17)   /* Bit 30..17:  Tx frame Length */
+#define XM_ST_RETRY_CNT        (0x1fL<<12)     /* Bit 16..12:  Retry Count */
+#define XM_ST_EX_COL   (1L<<11)        /* Bit 11:      Excessive Collisions */
+#define XM_ST_EX_DEF   (1L<<10)        /* Bit 10:      Excessive Deferral */
+#define XM_ST_BURST            (1L<<9)         /* Bit  9:      p. xmitted in burst md*/
+#define XM_ST_DEFER            (1L<<8)         /* Bit  8:      packet was defered */
+#define XM_ST_BC               (1L<<7)         /* Bit  7:      Broadcast packet */
+#define XM_ST_MC               (1L<<6)         /* Bit  6:      Multicast packet */
+#define XM_ST_UC               (1L<<5)         /* Bit  5:      Unicast packet */
+#define XM_ST_TX_UR            (1L<<4)         /* Bit  4:      FIFO Underrun occured */
+#define XM_ST_CS_ERR   (1L<<3)         /* Bit  3:      Carrier Sense Error */
+#define XM_ST_LAT_COL  (1L<<2)         /* Bit  2:      Late Collision Error */
+#define XM_ST_MUL_COL  (1L<<1)         /* Bit  1:      Multiple Collisions */
+#define XM_ST_SGN_COL  (1L<<0)         /* Bit  0:      Single Collision */
+
+/*     XM_RX_LO_WM     16 bit r/w      Receive Low Water Mark */
+/*     XM_RX_HI_WM     16 bit r/w      Receive High Water Mark */
+                                                                       /* Bit 15..11:  reserved */
+#define XM_RX_WM_MSK   0x03ff          /* Bit 11.. 0:  Rx FIFO Watermark bits */
+
+
+/*     XM_DEV_ID       32 bit r/o      Device ID Register */
+#define XM_DEV_OUI     (0x00ffffffUL<<8)       /* Bit 31..8:   Device OUI */
+#define XM_DEV_REV     (0x07L << 5)            /* Bit  7..5:   Chip Rev Num */
+
+
+/*     XM_MODE         32 bit r/w      Mode Register */
+                                                                       /* Bit 31..27:  reserved */
+#define XM_MD_ENA_REJ  (1L<<26)        /* Bit 26:      Enable Frame Reject */
+#define XM_MD_SPOE_E   (1L<<25)        /* Bit 25:      Send Pause on Edge */
+                                                                       /*              extern generated */
+#define XM_MD_TX_REP   (1L<<24)        /* Bit 24:      Transmit Repeater Mode */
+#define XM_MD_SPOFF_I  (1L<<23)        /* Bit 23:      Send Pause on FIFO full */
+                                                                       /*              intern generated */
+#define XM_MD_LE_STW   (1L<<22)        /* Bit 22:      Rx Stat Word in Little Endian */
+#define XM_MD_TX_CONT  (1L<<21)        /* Bit 21:      Send Continuous */
+#define XM_MD_TX_PAUSE (1L<<20)        /* Bit 20: (sc) Send Pause Frame */
+#define XM_MD_ATS              (1L<<19)        /* Bit 19:      Append Time Stamp */
+#define XM_MD_SPOL_I   (1L<<18)        /* Bit 18:      Send Pause on Low */
+                                                                       /*              intern generated */
+#define XM_MD_SPOH_I   (1L<<17)        /* Bit 17:      Send Pause on High */
+                                                                       /*              intern generated */
+#define XM_MD_CAP              (1L<<16)        /* Bit 16:      Check Address Pair */
+#define XM_MD_ENA_HASH (1L<<15)        /* Bit 15:      Enable Hashing */
+#define XM_MD_CSA              (1L<<14)        /* Bit 14:      Check Station Address */
+#define XM_MD_CAA              (1L<<13)        /* Bit 13:      Check Address Array */
+#define XM_MD_RX_MCTRL (1L<<12)        /* Bit 12:      Rx MAC Control Frame */
+#define XM_MD_RX_RUNT  (1L<<11)        /* Bit 11:      Rx Runt Frames */
+#define XM_MD_RX_IRLE  (1L<<10)        /* Bit 10:      Rx in Range Len Err Frame */
+#define XM_MD_RX_LONG  (1L<<9)         /* Bit  9:      Rx Long Frame */
+#define XM_MD_RX_CRCE  (1L<<8)         /* Bit  8:      Rx CRC Error Frame */
+#define XM_MD_RX_ERR   (1L<<7)         /* Bit  7:      Rx Error Frame */
+#define XM_MD_DIS_UC   (1L<<6)         /* Bit  6:      Disable Rx Unicast */
+#define XM_MD_DIS_MC   (1L<<5)         /* Bit  5:      Disable Rx Multicast */
+#define XM_MD_DIS_BC   (1L<<4)         /* Bit  4:      Disable Rx Broadcast */
+#define XM_MD_ENA_PROM (1L<<3)         /* Bit  3:      Enable Promiscuous */
+#define XM_MD_ENA_BE   (1L<<2)         /* Bit  2:      Enable Big Endian */
+#define XM_MD_FTF              (1L<<1)         /* Bit  1: (sc) Flush Tx FIFO */
+#define XM_MD_FRF              (1L<<0)         /* Bit  0: (sc) Flush Rx FIFO */
+
+#define XM_PAUSE_MODE  (XM_MD_SPOE_E | XM_MD_SPOL_I | XM_MD_SPOH_I)
+#define XM_DEF_MODE            (XM_MD_RX_RUNT | XM_MD_RX_IRLE | XM_MD_RX_LONG |\
+                               XM_MD_RX_CRCE | XM_MD_RX_ERR | XM_MD_CSA | XM_MD_CAA)
+
+/*     XM_STAT_CMD     16 bit r/w      Statistics Command Register */
+                                                               /* Bit 16..6:   reserved */
+#define XM_SC_SNP_RXC  (1<<5)  /* Bit  5: (sc) Snap Rx Counters */
+#define XM_SC_SNP_TXC  (1<<4)  /* Bit  4: (sc) Snap Tx Counters */
+#define XM_SC_CP_RXC   (1<<3)  /* Bit  3:      Copy Rx Counters Continuously */
+#define XM_SC_CP_TXC   (1<<2)  /* Bit  2:      Copy Tx Counters Continuously */
+#define XM_SC_CLR_RXC  (1<<1)  /* Bit  1: (sc) Clear Rx Counters */
+#define XM_SC_CLR_TXC  (1<<0)  /* Bit  0: (sc) Clear Tx Counters */
+
+
+/*     XM_RX_CNT_EV    32 bit r/o      Rx Counter Event Register */
+/*     XM_RX_EV_MSK    32 bit r/w      Rx Counter Event Mask */
+#define XMR_MAX_SZ_OV  (1UL<<31)       /* Bit 31:      1024-MaxSize Rx Cnt Ov*/
+#define XMR_1023B_OV   (1L<<30)        /* Bit 30:      512-1023Byte Rx Cnt Ov*/
+#define XMR_511B_OV            (1L<<29)        /* Bit 29:      256-511 Byte Rx Cnt Ov*/
+#define XMR_255B_OV            (1L<<28)        /* Bit 28:      128-255 Byte Rx Cnt Ov*/
+#define XMR_127B_OV            (1L<<27)        /* Bit 27:      65-127 Byte Rx Cnt Ov */
+#define XMR_64B_OV             (1L<<26)        /* Bit 26:      64 Byte Rx Cnt Ov */
+#define XMR_UTIL_OV            (1L<<25)        /* Bit 25:      Rx Util Cnt Overflow */
+#define XMR_UTIL_UR            (1L<<24)        /* Bit 24:      Rx Util Cnt Underrun */
+#define XMR_CEX_ERR_OV (1L<<23)        /* Bit 23:      CEXT Err Cnt Ov */
+                                                                       /* Bit 22:      reserved */
+#define XMR_FCS_ERR_OV (1L<<21)        /* Bit 21:      Rx FCS Error Cnt Ov */
+#define XMR_LNG_ERR_OV (1L<<20)        /* Bit 20:      Rx too Long Err Cnt Ov*/
+#define XMR_RUNT_OV            (1L<<19)        /* Bit 19:      Runt Event Cnt Ov */
+#define XMR_SHT_ERR_OV (1L<<18)        /* Bit 18:      Rx Short Ev Err Cnt Ov*/
+#define XMR_SYM_ERR_OV (1L<<17)        /* Bit 17:      Rx Sym Err Cnt Ov */
+                                                                       /* Bit 16:      reserved */
+#define XMR_CAR_ERR_OV (1L<<15)        /* Bit 15:      Rx Carr Ev Err Cnt Ov */
+#define XMR_JAB_PKT_OV (1L<<14)        /* Bit 14:      Rx Jabb Packet Cnt Ov */
+#define XMR_FIFO_OV            (1L<<13)        /* Bit 13:      Rx FIFO Ov Ev Cnt Ov */
+#define XMR_FRA_ERR_OV (1L<<12)        /* Bit 12:      Rx Framing Err Cnt Ov */
+#define XMR_FMISS_OV   (1L<<11)        /* Bit 11:      Rx Missed Ev Cnt Ov */
+#define XMR_BURST              (1L<<10)        /* Bit 10:      Rx Burst Event Cnt Ov */
+#define XMR_INV_MOC            (1L<<9)         /* Bit  9:      Rx with inv. MAC OC Ov*/
+#define XMR_INV_MP             (1L<<8)         /* Bit  8:      Rx inv Pause Frame Ov */
+#define XMR_MCTRL_OV   (1L<<7)         /* Bit  7:      Rx MAC Ctrl-F Cnt Ov */
+#define XMR_MPAUSE_OV  (1L<<6)         /* Bit  6:      Rx Pause MAC Ctrl-F Ov*/
+#define XMR_UC_OK_OV   (1L<<5)         /* Bit  5:      Rx Unicast Frame CntOv*/
+#define XMR_MC_OK_OV   (1L<<4)         /* Bit  4:      Rx Multicast Cnt Ov */
+#define XMR_BC_OK_OV   (1L<<3)         /* Bit  3:      Rx Broadcast Cnt Ov */
+#define XMR_OK_LO_OV   (1L<<2)         /* Bit  2:      Octets Rx OK Low CntOv*/
+#define XMR_OK_HI_OV   (1L<<1)         /* Bit  1:      Octets Rx OK Hi Cnt Ov*/
+#define XMR_OK_OV              (1L<<0)         /* Bit  0:      Frames Received Ok Ov */
+
+#define XMR_DEF_MSK            (XMR_OK_LO_OV | XMR_OK_HI_OV)
+
+/*     XM_TX_CNT_EV    32 bit r/o      Tx Counter Event Register */
+/*     XM_TX_EV_MSK    32 bit r/w      Tx Counter Event Mask */
+                                                                       /* Bit 31..26:  reserved */
+#define XMT_MAX_SZ_OV  (1L<<25)        /* Bit 25:      1024-MaxSize Tx Cnt Ov*/
+#define XMT_1023B_OV   (1L<<24)        /* Bit 24:      512-1023Byte Tx Cnt Ov*/
+#define XMT_511B_OV            (1L<<23)        /* Bit 23:      256-511 Byte Tx Cnt Ov*/
+#define XMT_255B_OV            (1L<<22)        /* Bit 22:      128-255 Byte Tx Cnt Ov*/
+#define XMT_127B_OV            (1L<<21)        /* Bit 21:      65-127 Byte Tx Cnt Ov */
+#define XMT_64B_OV             (1L<<20)        /* Bit 20:      64 Byte Tx Cnt Ov */
+#define XMT_UTIL_OV            (1L<<19)        /* Bit 19:      Tx Util Cnt Overflow */
+#define XMT_UTIL_UR            (1L<<18)        /* Bit 18:      Tx Util Cnt Underrun */
+#define XMT_CS_ERR_OV  (1L<<17)        /* Bit 17:      Tx Carr Sen Err Cnt Ov*/
+#define XMT_FIFO_UR_OV (1L<<16)        /* Bit 16:      Tx FIFO Ur Ev Cnt Ov */
+#define XMT_EX_DEF_OV  (1L<<15)        /* Bit 15:      Tx Ex Deferall Cnt Ov */
+#define XMT_DEF                        (1L<<14)        /* Bit 14:      Tx Deferred Cnt Ov */
+#define XMT_LAT_COL_OV (1L<<13)        /* Bit 13:      Tx Late Col Cnt Ov */
+#define XMT_ABO_COL_OV (1L<<12)        /* Bit 12:      Tx abo dueto Ex Col Ov*/
+#define XMT_MUL_COL_OV (1L<<11)        /* Bit 11:      Tx Mult Col Cnt Ov */
+#define XMT_SNG_COL            (1L<<10)        /* Bit 10:      Tx Single Col Cnt Ov */
+#define XMT_MCTRL_OV   (1L<<9)         /* Bit  9:      Tx MAC Ctrl Counter Ov*/
+#define XMT_MPAUSE             (1L<<8)         /* Bit  8:      Tx Pause MAC Ctrl-F Ov*/
+#define XMT_BURST              (1L<<7)         /* Bit  7:      Tx Burst Event Cnt Ov */
+#define XMT_LONG               (1L<<6)         /* Bit  6:      Tx Long Frame Cnt Ov */
+#define XMT_UC_OK_OV   (1L<<5)         /* Bit  5:      Tx Unicast Cnt Ov */
+#define XMT_MC_OK_OV   (1L<<4)         /* Bit  4:      Tx Multicast Cnt Ov */
+#define XMT_BC_OK_OV   (1L<<3)         /* Bit  3:      Tx Broadcast Cnt Ov */
+#define XMT_OK_LO_OV   (1L<<2)         /* Bit  2:      Octets Tx OK Low CntOv*/
+#define XMT_OK_HI_OV   (1L<<1)         /* Bit  1:      Octets Tx OK Hi Cnt Ov*/
+#define XMT_OK_OV              (1L<<0)         /* Bit  0:      Frames Tx Ok Ov */
+
+#define XMT_DEF_MSK            (XMT_OK_LO_OV | XMT_OK_HI_OV)
+
+/*
+ * Receive Frame Status Encoding
+ */
+#define XMR_FS_LEN     (0x3fffUL<<18)  /* Bit 31..18:  Rx Frame Length */
+#define XMR_FS_2L_VLAN (1L<<17)        /* Bit 17:      tagged wh 2Lev VLAN ID*/
+#define XMR_FS_1L_VLAN (1L<<16)        /* Bit 16:      tagged wh 1Lev VLAN ID*/
+#define XMR_FS_BC              (1L<<15)        /* Bit 15:      Broadcast Frame */
+#define XMR_FS_MC              (1L<<14)        /* Bit 14:      Multicast Frame */
+#define XMR_FS_UC              (1L<<13)        /* Bit 13:      Unicast Frame */
+                                                                       /* Bit 12:      reserved */
+#define XMR_FS_BURST   (1L<<11)        /* Bit 11:      Burst Mode */
+#define XMR_FS_CEX_ERR (1L<<10)        /* Bit 10:      Carrier Ext. Error */
+#define XMR_FS_802_3   (1L<<9)         /* Bit  9:      802.3 Frame */
+#define XMR_FS_COL_ERR (1L<<8)         /* Bit  8:      Collision Error */
+#define XMR_FS_CAR_ERR (1L<<7)         /* Bit  7:      Carrier Event Error */
+#define XMR_FS_LEN_ERR (1L<<6)         /* Bit  6:      In-Range Length Error */
+#define XMR_FS_FRA_ERR (1L<<5)         /* Bit  5:      Framing Error */
+#define XMR_FS_RUNT            (1L<<4)         /* Bit  4:      Runt Frame */
+#define XMR_FS_LNG_ERR (1L<<3)         /* Bit  3:      Giant (Jumbo) Frame */
+#define XMR_FS_FCS_ERR (1L<<2)         /* Bit  2:      Frame Check Sequ Err */
+#define XMR_FS_ERR             (1L<<1)         /* Bit  1:      Frame Error */
+#define XMR_FS_MCTRL   (1L<<0)         /* Bit  0:      MAC Control Packet */
+
+/*
+ * XMR_FS_ERR will be set if
+ *     XMR_FS_FCS_ERR, XMR_FS_LNG_ERR, XMR_FS_RUNT,
+ *     XMR_FS_FRA_ERR, XMR_FS_LEN_ERR, or XMR_FS_CEX_ERR
+ * is set. XMR_FS_LNG_ERR and XMR_FS_LEN_ERR will issue
+ * XMR_FS_ERR unless the corresponding bit in the Receive Command
+ * Register is set.
+ */
+#define XMR_FS_ANY_ERR XMR_FS_ERR
+
+/*----------------------------------------------------------------------------*/
+/*
+ * XMAC-PHY Registers, indirect addressed over the XMAC
+ */
+#define PHY_XMAC_CTRL          0x00    /* 16 bit r/w   PHY Control Register */
+#define PHY_XMAC_STAT          0x01    /* 16 bit r/w   PHY Status Register */
+#define PHY_XMAC_ID0           0x02    /* 16 bit r/o   PHY ID0 Register */
+#define PHY_XMAC_ID1           0x03    /* 16 bit r/o   PHY ID1 Register */
+#define PHY_XMAC_AUNE_ADV      0x04    /* 16 bit r/w   Auto-Neg. Advertisement */
+#define PHY_XMAC_AUNE_LP       0x05    /* 16 bit r/o   Link Partner Abi Reg */
+#define PHY_XMAC_AUNE_EXP      0x06    /* 16 bit r/o   Auto-Neg. Expansion Reg */
+#define PHY_XMAC_NEPG          0x07    /* 16 bit r/w   Next Page Register */
+#define PHY_XMAC_NEPG_LP       0x08    /* 16 bit r/o   Next Page Link Partner */
+       /* 0x09 - 0x0e:         reserved */
+#define PHY_XMAC_EXT_STAT      0x0f    /* 16 bit r/o   Ext Status Register */
+#define PHY_XMAC_RES_ABI       0x10    /* 16 bit r/o   PHY Resolved Ability */
+
+/*----------------------------------------------------------------------------*/
+/*
+ * Broadcom-PHY Registers, indirect addressed over XMAC
+ */
+#define PHY_BCOM_CTRL          0x00    /* 16 bit r/w   PHY Control Register */
+#define PHY_BCOM_STAT          0x01    /* 16 bit r/o   PHY Status Register */
+#define PHY_BCOM_ID0           0x02    /* 16 bit r/o   PHY ID0 Register */
+#define PHY_BCOM_ID1           0x03    /* 16 bit r/o   PHY ID1 Register */
+#define PHY_BCOM_AUNE_ADV      0x04    /* 16 bit r/w   Auto-Neg. Advertisement */
+#define PHY_BCOM_AUNE_LP       0x05    /* 16 bit r/o   Link Part Ability Reg */
+#define PHY_BCOM_AUNE_EXP      0x06    /* 16 bit r/o   Auto-Neg. Expansion Reg */
+#define PHY_BCOM_NEPG          0x07    /* 16 bit r/w   Next Page Register */
+#define PHY_BCOM_NEPG_LP       0x08    /* 16 bit r/o   Next Page Link Partner */
+       /* Broadcom-specific registers */
+#define PHY_BCOM_1000T_CTRL    0x09    /* 16 bit r/w   1000Base-T Ctrl Reg */
+#define PHY_BCOM_1000T_STAT    0x0a    /* 16 bit r/o   1000Base-T Status Reg */
+       /* 0x0b - 0x0e:         reserved */
+#define PHY_BCOM_EXT_STAT      0x0f    /* 16 bit r/o   Extended Status Reg */
+#define PHY_BCOM_P_EXT_CTRL    0x10    /* 16 bit r/w   PHY Extended Ctrl Reg */
+#define PHY_BCOM_P_EXT_STAT    0x11    /* 16 bit r/o   PHY Extended Stat Reg */
+#define PHY_BCOM_RE_CTR                0x12    /* 16 bit r/w   Receive Error Counter */
+#define PHY_BCOM_FC_CTR                0x13    /* 16 bit r/w   False Carrier Sense Cnt */
+#define PHY_BCOM_RNO_CTR       0x14    /* 16 bit r/w   Receiver NOT_OK Cnt */
+       /* 0x15 - 0x17:         reserved */
+#define PHY_BCOM_AUX_CTRL      0x18    /* 16 bit r/w   Auxiliary Control Reg */
+#define PHY_BCOM_AUX_STAT      0x19    /* 16 bit r/o   Auxiliary Stat Summary */
+#define PHY_BCOM_INT_STAT      0x1a    /* 16 bit r/o   Interrupt Status Reg */
+#define PHY_BCOM_INT_MASK      0x1b    /* 16 bit r/w   Interrupt Mask Reg */
+       /* 0x1c:                reserved */
+       /* 0x1d - 0x1f:         test registers */
+
+/*----------------------------------------------------------------------------*/
+/*
+ * Marvel-PHY Registers, indirect addressed over GMAC
+ */
+#define PHY_MARV_CTRL          0x00    /* 16 bit r/w   PHY Control Register */
+#define PHY_MARV_STAT          0x01    /* 16 bit r/o   PHY Status Register */
+#define PHY_MARV_ID0           0x02    /* 16 bit r/o   PHY ID0 Register */
+#define PHY_MARV_ID1           0x03    /* 16 bit r/o   PHY ID1 Register */
+#define PHY_MARV_AUNE_ADV      0x04    /* 16 bit r/w   Auto-Neg. Advertisement */
+#define PHY_MARV_AUNE_LP       0x05    /* 16 bit r/o   Link Part Ability Reg */
+#define PHY_MARV_AUNE_EXP      0x06    /* 16 bit r/o   Auto-Neg. Expansion Reg */
+#define PHY_MARV_NEPG          0x07    /* 16 bit r/w   Next Page Register */
+#define PHY_MARV_NEPG_LP       0x08    /* 16 bit r/o   Next Page Link Partner */
+       /* Marvel-specific registers */
+#define PHY_MARV_1000T_CTRL    0x09    /* 16 bit r/w   1000Base-T Ctrl Reg */
+#define PHY_MARV_1000T_STAT    0x0a    /* 16 bit r/o   1000Base-T Status Reg */
+       /* 0x0b - 0x0e:         reserved */
+#define PHY_MARV_EXT_STAT      0x0f    /* 16 bit r/o   Extended Status Reg */
+#define PHY_MARV_PHY_CTRL      0x10    /* 16 bit r/w   PHY Specific Ctrl Reg */
+#define PHY_MARV_PHY_STAT      0x11    /* 16 bit r/o   PHY Specific Stat Reg */
+#define PHY_MARV_INT_MASK      0x12    /* 16 bit r/w   Interrupt Mask Reg */
+#define PHY_MARV_INT_STAT      0x13    /* 16 bit r/o   Interrupt Status Reg */
+#define PHY_MARV_EXT_CTRL      0x14    /* 16 bit r/w   Ext. PHY Specific Ctrl */
+#define PHY_MARV_RXE_CNT       0x15    /* 16 bit r/w   Receive Error Counter */
+#define PHY_MARV_EXT_ADR       0x16    /* 16 bit r/w   Ext. Ad. for Cable Diag. */
+       /* 0x17:                reserved */
+#define PHY_MARV_LED_CTRL      0x18    /* 16 bit r/w   LED Control Reg */
+#define PHY_MARV_LED_OVER      0x19    /* 16 bit r/w   Manual LED Override Reg */
+#define PHY_MARV_EXT_CTRL_2    0x1a    /* 16 bit r/w   Ext. PHY Specific Ctrl 2 */
+#define PHY_MARV_EXT_P_STAT    0x1b    /* 16 bit r/w   Ext. PHY Spec. Stat Reg */
+#define PHY_MARV_CABLE_DIAG    0x1c    /* 16 bit r/o   Cable Diagnostic Reg */
+       /* 0x1d - 0x1f:         reserved */
+
+/*----------------------------------------------------------------------------*/
+/*
+ * Level One-PHY Registers, indirect addressed over XMAC
+ */
+#define PHY_LONE_CTRL          0x00    /* 16 bit r/w   PHY Control Register */
+#define PHY_LONE_STAT          0x01    /* 16 bit r/o   PHY Status Register */
+#define PHY_LONE_ID0           0x02    /* 16 bit r/o   PHY ID0 Register */
+#define PHY_LONE_ID1           0x03    /* 16 bit r/o   PHY ID1 Register */
+#define PHY_LONE_AUNE_ADV      0x04    /* 16 bit r/w   Auto-Neg. Advertisement */
+#define PHY_LONE_AUNE_LP       0x05    /* 16 bit r/o   Link Part Ability Reg */
+#define PHY_LONE_AUNE_EXP      0x06    /* 16 bit r/o   Auto-Neg. Expansion Reg */
+#define PHY_LONE_NEPG          0x07    /* 16 bit r/w   Next Page Register */
+#define PHY_LONE_NEPG_LP       0x08    /* 16 bit r/o   Next Page Link Partner */
+       /* Level One-specific registers */
+#define PHY_LONE_1000T_CTRL    0x09    /* 16 bit r/w   1000Base-T Control Reg*/
+#define PHY_LONE_1000T_STAT    0x0a    /* 16 bit r/o   1000Base-T Status Reg */
+       /* 0x0b -0x0e:          reserved */
+#define PHY_LONE_EXT_STAT      0x0f    /* 16 bit r/o   Extended Status Reg */
+#define PHY_LONE_PORT_CFG      0x10    /* 16 bit r/w   Port Configuration Reg*/
+#define PHY_LONE_Q_STAT                0x11    /* 16 bit r/o   Quick Status Reg */
+#define PHY_LONE_INT_ENAB      0x12    /* 16 bit r/w   Interrupt Enable Reg */
+#define PHY_LONE_INT_STAT      0x13    /* 16 bit r/o   Interrupt Status Reg */
+#define PHY_LONE_LED_CFG       0x14    /* 16 bit r/w   LED Configuration Reg */
+#define PHY_LONE_PORT_CTRL     0x15    /* 16 bit r/w   Port Control Reg */
+#define PHY_LONE_CIM           0x16    /* 16 bit r/o   CIM Reg */
+       /* 0x17 -0x1c:          reserved */
+
+/*----------------------------------------------------------------------------*/
+/*
+ * National-PHY Registers, indirect addressed over XMAC
+ */
+#define PHY_NAT_CTRL           0x00    /* 16 bit r/w   PHY Control Register */
+#define PHY_NAT_STAT           0x01    /* 16 bit r/w   PHY Status Register */
+#define PHY_NAT_ID0                    0x02    /* 16 bit r/o   PHY ID0 Register */
+#define PHY_NAT_ID1                    0x03    /* 16 bit r/o   PHY ID1 Register */
+#define PHY_NAT_AUNE_ADV       0x04    /* 16 bit r/w   Auto-Neg. Advertisement */
+#define PHY_NAT_AUNE_LP                0x05    /* 16 bit r/o   Link Partner Ability Reg */
+#define PHY_NAT_AUNE_EXP       0x06    /* 16 bit r/o   Auto-Neg. Expansion Reg */
+#define PHY_NAT_NEPG           0x07    /* 16 bit r/w   Next Page Register */
+#define PHY_NAT_NEPG_LP                0x08    /* 16 bit r/o   Next Page Link Partner Reg */
+       /* National-specific registers */
+#define PHY_NAT_1000T_CTRL     0x09    /* 16 bit r/w   1000Base-T Control Reg */
+#define PHY_NAT_1000T_STAT     0x0a    /* 16 bit r/o   1000Base-T Status Reg */
+       /* 0x0b -0x0e:          reserved */
+#define PHY_NAT_EXT_STAT       0x0f    /* 16 bit r/o   Extended Status Register */
+#define PHY_NAT_EXT_CTRL1      0x10    /* 16 bit r/o   Extended Control Reg1 */
+#define PHY_NAT_Q_STAT1                0x11    /* 16 bit r/o   Quick Status Reg1 */
+#define PHY_NAT_10B_OP         0x12    /* 16 bit r/o   10Base-T Operations Reg */
+#define PHY_NAT_EXT_CTRL2      0x13    /* 16 bit r/o   Extended Control Reg1 */
+#define PHY_NAT_Q_STAT2                0x14    /* 16 bit r/o   Quick Status Reg2 */
+       /* 0x15 -0x18:          reserved */
+#define PHY_NAT_PHY_ADDR       0x19    /* 16 bit r/o   PHY Address Register */
+
+
+/*----------------------------------------------------------------------------*/
+
+/*
+ * PHY bit definitions
+ * Bits defined as PHY_X_..., PHY_B_..., PHY_L_... or PHY_N_... are
+ * XMAC/Broadcom/LevelOne/National/Marvell-specific.
+ * All other are general.
+ */
+
+/*****  PHY_XMAC_CTRL  16 bit r/w      PHY Control Register *****/
+/*****  PHY_BCOM_CTRL  16 bit r/w      PHY Control Register *****/
+/*****  PHY_MARV_CTRL  16 bit r/w      PHY Status Register *****/
+/*****  PHY_LONE_CTRL  16 bit r/w      PHY Control Register *****/
+#define PHY_CT_RESET   (1<<15) /* Bit 15: (sc) clear all PHY related regs */
+#define PHY_CT_LOOP            (1<<14) /* Bit 14:      enable Loopback over PHY */
+#define PHY_CT_SPS_LSB (1<<13) /* Bit 13: (BC,L1) Speed select, lower bit */
+#define PHY_CT_ANE             (1<<12) /* Bit 12:      Auto-Negotiation Enabled */
+#define PHY_CT_PDOWN   (1<<11) /* Bit 11: (BC,L1) Power Down Mode */
+#define PHY_CT_ISOL            (1<<10) /* Bit 10: (BC,L1) Isolate Mode */
+#define PHY_CT_RE_CFG  (1<<9)  /* Bit  9: (sc) Restart Auto-Negotiation */
+#define PHY_CT_DUP_MD  (1<<8)  /* Bit  8:      Duplex Mode */
+#define PHY_CT_COL_TST (1<<7)  /* Bit  7: (BC,L1) Collision Test enabled */
+#define PHY_CT_SPS_MSB (1<<6)  /* Bit  6: (BC,L1) Speed select, upper bit */
+                                                               /* Bit  5..0:   reserved */
+
+#define PHY_CT_SP1000  PHY_CT_SPS_MSB  /* enable speed of 1000 Mbps */
+#define PHY_CT_SP100   PHY_CT_SPS_LSB  /* enable speed of  100 Mbps */
+#define PHY_CT_SP10            (0)                             /* enable speed of   10 Mbps */
+
+
+/*****  PHY_XMAC_STAT  16 bit r/w      PHY Status Register *****/
+/*****  PHY_BCOM_STAT  16 bit r/w      PHY Status Register *****/
+/*****  PHY_MARV_STAT  16 bit r/w      PHY Status Register *****/
+/*****  PHY_LONE_STAT  16 bit r/w      PHY Status Register *****/
+                                                               /* Bit 15..9:   reserved */
+                               /*      (BC/L1) 100/10 Mbps cap bits ignored*/
+#define PHY_ST_EXT_ST  (1<<8)  /* Bit  8:      Extended Status Present */
+                                                               /* Bit  7:      reserved */
+#define PHY_ST_PRE_SUP (1<<6)  /* Bit  6: (BC/L1) preamble suppression */
+#define PHY_ST_AN_OVER (1<<5)  /* Bit  5:      Auto-Negotiation Over */
+#define PHY_ST_REM_FLT (1<<4)  /* Bit  4:      Remote Fault Condition Occured */
+#define PHY_ST_AN_CAP  (1<<3)  /* Bit  3:      Auto-Negotiation Capability */
+#define PHY_ST_LSYNC   (1<<2)  /* Bit  2:      Link Synchronized */
+#define PHY_ST_JAB_DET (1<<1)  /* Bit  1: (BC/L1) Jabber Detected */
+#define PHY_ST_EXT_REG (1<<0)  /* Bit  0:      Extended Register available */
+
+
+/***** PHY_XMAC_ID1            16 bit r/o      PHY ID1 Register */
+/***** PHY_BCOM_ID1            16 bit r/o      PHY ID1 Register */
+/***** PHY_MARV_ID1            16 bit r/o      PHY ID1 Register */
+/***** PHY_LONE_ID1            16 bit r/o      PHY ID1 Register */
+#define PHY_I1_OUI_MSK (0x3f<<10)      /* Bit 15..10:  Organization Unique ID */
+#define PHY_I1_MOD_NUM (0x3f<<4)       /* Bit  9.. 4:  Model Number */
+#define PHY_I1_REV_MSK 0x0f            /* Bit  3.. 0:  Revision Number */
+
+/* different Broadcom PHY Ids */
+#define PHY_BCOM_ID1_A1                0x6041
+#define PHY_BCOM_ID1_B2                0x6043
+#define PHY_BCOM_ID1_C0                0x6044
+#define PHY_BCOM_ID1_C5                0x6047
+
+
+/*****  PHY_XMAC_AUNE_ADV      16 bit r/w      Auto-Negotiation Advertisement *****/
+/*****  PHY_XMAC_AUNE_LP       16 bit r/o      Link Partner Ability Reg *****/
+#define PHY_AN_NXT_PG  (1<<15) /* Bit 15:      Request Next Page */
+#define PHY_X_AN_ACK   (1<<14) /* Bit 14: (ro) Acknowledge Received */
+#define PHY_X_AN_RFB   (3<<12) /* Bit 13..12:  Remote Fault Bits */
+                                                               /* Bit 11.. 9:  reserved */
+#define PHY_X_AN_PAUSE (3<<7)  /* Bit  8.. 7:  Pause Bits */
+#define PHY_X_AN_HD            (1<<6)  /* Bit  6:      Half Duplex */
+#define PHY_X_AN_FD            (1<<5)  /* Bit  5:      Full Duplex */
+                                                               /* Bit  4.. 0:  reserved */
+
+/*****  PHY_BCOM_AUNE_ADV      16 bit r/w      Auto-Negotiation Advertisement *****/
+/*****  PHY_BCOM_AUNE_LP       16 bit r/o      Link Partner Ability Reg *****/
+/*     PHY_AN_NXT_PG           (see XMAC) Bit 15:      Request Next Page */
+                                                               /* Bit 14:      reserved */
+#define PHY_B_AN_RF            (1<<13) /* Bit 13:      Remote Fault */
+                                                               /* Bit 12:      reserved */
+#define PHY_B_AN_ASP   (1<<11) /* Bit 11:      Asymmetric Pause */
+#define PHY_B_AN_PC            (1<<10) /* Bit 10:      Pause Capable */
+                                                               /* Bit  9..5:   100/10 BT cap bits ingnored */
+#define PHY_B_AN_SEL   0x1f    /* Bit 4..0:    Selector Field, 00001=Ethernet*/
+
+/*****  PHY_LONE_AUNE_ADV      16 bit r/w      Auto-Negotiation Advertisement *****/
+/*****  PHY_LONE_AUNE_LP       16 bit r/o      Link Partner Ability Reg *****/
+/*     PHY_AN_NXT_PG           (see XMAC) Bit 15:      Request Next Page */
+                                                               /* Bit 14:      reserved */
+#define PHY_L_AN_RF            (1<<13) /* Bit 13:      Remote Fault */
+                                                               /* Bit 12:      reserved */
+#define PHY_L_AN_ASP   (1<<11) /* Bit 11:      Asymmetric Pause */
+#define PHY_L_AN_PC            (1<<10) /* Bit 10:      Pause Capable */
+                                                               /* Bit  9..5:   100/10 BT cap bits ingnored */
+#define PHY_L_AN_SEL   0x1f    /* Bit 4..0:    Selector Field, 00001=Ethernet*/
+
+/*****  PHY_NAT_AUNE_ADV       16 bit r/w      Auto-Negotiation Advertisement *****/
+/*****  PHY_NAT_AUNE_LP                16 bit r/o      Link Partner Ability Reg *****/
+/*     PHY_AN_NXT_PG           (see XMAC) Bit 15:      Request Next Page */
+                                                               /* Bit 14:      reserved */
+#define PHY_N_AN_RF            (1<<13) /* Bit 13:      Remote Fault */
+                                                               /* Bit 12:      reserved */
+#define PHY_N_AN_100F  (1<<11) /* Bit 11:      100Base-T2 FD Support */
+#define PHY_N_AN_100H  (1<<10) /* Bit 10:      100Base-T2 HD Support */
+                                                               /* Bit  9..5:   100/10 BT cap bits ingnored */
+#define PHY_N_AN_SEL   0x1f    /* Bit 4..0:    Selector Field, 00001=Ethernet*/
+
+/* field type definition for PHY_x_AN_SEL */
+#define PHY_SEL_TYPE   0x01    /* 00001 = Ethernet */
+
+/*****  PHY_XMAC_AUNE_EXP      16 bit r/o      Auto-Negotiation Expansion Reg *****/
+                                                               /* Bit 15..4:   reserved */
+#define PHY_ANE_LP_NP  (1<<3)  /* Bit  3:      Link Partner can Next Page */
+#define PHY_ANE_LOC_NP (1<<2)  /* Bit  2:      Local PHY can Next Page */
+#define PHY_ANE_RX_PG  (1<<1)  /* Bit  1:      Page Received */
+                                                               /* Bit  0:      reserved */
+
+/*****  PHY_BCOM_AUNE_EXP      16 bit r/o      Auto-Negotiation Expansion Reg *****/
+/*****  PHY_LONE_AUNE_EXP      16 bit r/o      Auto-Negotiation Expansion Reg *****/
+/*****  PHY_MARV_AUNE_EXP      16 bit r/o      Auto-Negotiation Expansion Reg *****/
+                                                               /* Bit 15..5:   reserved */
+#define PHY_ANE_PAR_DF (1<<4)  /* Bit  4:      Parallel Detection Fault */
+/*     PHY_ANE_LP_NP           (see XMAC) Bit  3:      Link Partner can Next Page */
+/*     PHY_ANE_LOC_NP          (see XMAC) Bit  2:      Local PHY can Next Page */
+/*     PHY_ANE_RX_PG           (see XMAC) Bit  1:      Page Received */
+#define PHY_ANE_LP_CAP (1<<0)  /* Bit  0:      Link Partner Auto-Neg. Cap. */  
+
+/*****  PHY_XMAC_NEPG          16 bit r/w      Next Page Register *****/
+/*****  PHY_BCOM_NEPG          16 bit r/w      Next Page Register *****/
+/*****  PHY_LONE_NEPG          16 bit r/w      Next Page Register *****/
+/*****  PHY_XMAC_NEPG_LP       16 bit r/o      Next Page Link Partner *****/
+/*****  PHY_BCOM_NEPG_LP       16 bit r/o      Next Page Link Partner *****/
+/*****  PHY_LONE_NEPG_LP       16 bit r/o      Next Page Link Partner *****/
+#define PHY_NP_MORE            (1<<15) /* Bit 15:      More, Next Pages to follow */
+#define PHY_NP_ACK1            (1<<14) /* Bit 14: (ro) Ack1, for receiving a message */
+#define PHY_NP_MSG_VAL (1<<13) /* Bit 13:      Message Page valid */
+#define PHY_NP_ACK2            (1<<12) /* Bit 12:      Ack2, comply with msg content */
+#define PHY_NP_TOG             (1<<11) /* Bit 11:      Toggle Bit, ensure sync */
+#define PHY_NP_MSG             0x07ff  /* Bit 10..0:   Message from/to Link Partner */
+
+/*
+ * XMAC-Specific
+ */
+/*****  PHY_XMAC_EXT_STAT      16 bit r/w      Extended Status Register *****/
+#define PHY_X_EX_FD            (1<<15) /* Bit 15:      Device Supports Full Duplex */
+#define PHY_X_EX_HD            (1<<14) /* Bit 14:      Device Supports Half Duplex */
+                                                               /* Bit 13..0:   reserved */
+
+/*****  PHY_XMAC_RES_ABI       16 bit r/o      PHY Resolved Ability *****/
+                                                               /* Bit 15..9:   reserved */
+#define PHY_X_RS_PAUSE (3<<7)  /* Bit  8..7:   selected Pause Mode */
+#define PHY_X_RS_HD            (1<<6)  /* Bit  6:      Half Duplex Mode selected */
+#define PHY_X_RS_FD            (1<<5)  /* Bit  5:      Full Duplex Mode selected */
+#define PHY_X_RS_ABLMIS (1<<4) /* Bit  4:      duplex or pause cap mismatch */
+#define PHY_X_RS_PAUMIS (1<<3) /* Bit  3:      pause capability mismatch */
+                                                               /* Bit  2..0:   reserved */
+/*
+ * Remote Fault Bits (PHY_X_AN_RFB) encoding
+ */
+#define X_RFB_OK               (0<<12) /* Bit 13..12   No errors, Link OK */
+#define X_RFB_LF               (1<<12) /* Bit 13..12   Link Failure */
+#define X_RFB_OFF              (2<<12) /* Bit 13..12   Offline */
+#define X_RFB_AN_ERR   (3<<12) /* Bit 13..12   Auto-Negotiation Error */
+
+/*
+ * Pause Bits (PHY_X_AN_PAUSE and PHY_X_RS_PAUSE) encoding
+ */
+#define PHY_X_P_NO_PAUSE       (0<<7)  /* Bit  8..7:   no Pause Mode */
+#define PHY_X_P_SYM_MD         (1<<7)  /* Bit  8..7:   symmetric Pause Mode */
+#define PHY_X_P_ASYM_MD                (2<<7)  /* Bit  8..7:   asymmetric Pause Mode */
+#define PHY_X_P_BOTH_MD                (3<<7)  /* Bit  8..7:   both Pause Mode */
+
+
+/*
+ * Broadcom-Specific
+ */
+/*****  PHY_BCOM_1000T_CTRL    16 bit r/w      1000Base-T Control Reg *****/
+#define PHY_B_1000C_TEST       (7<<13) /* Bit 15..13:  Test Modes */
+#define PHY_B_1000C_MSE                (1<<12) /* Bit 12:      Master/Slave Enable */
+#define PHY_B_1000C_MSC                (1<<11) /* Bit 11:      M/S Configuration */
+#define PHY_B_1000C_RD         (1<<10) /* Bit 10:      Repeater/DTE */
+#define PHY_B_1000C_AFD                (1<<9)  /* Bit  9:      Advertise Full Duplex */
+#define PHY_B_1000C_AHD                (1<<8)  /* Bit  8:      Advertise Half Duplex */
+                                                                       /* Bit  7..0:   reserved */
+
+/*****  PHY_BCOM_1000T_STAT    16 bit r/o      1000Base-T Status Reg *****/
+/*****  PHY_MARV_1000T_STAT    16 bit r/o      1000Base-T Status Reg *****/
+#define PHY_B_1000S_MSF                (1<<15) /* Bit 15:      Master/Slave Fault */
+#define PHY_B_1000S_MSR                (1<<14) /* Bit 14:      Master/Slave Result */
+#define PHY_B_1000S_LRS                (1<<13) /* Bit 13:      Local Receiver Status */
+#define PHY_B_1000S_RRS                (1<<12) /* Bit 12:      Remote Receiver Status */
+#define PHY_B_1000S_LP_FD      (1<<11) /* Bit 11:      Link Partner can FD */
+#define PHY_B_1000S_LP_HD      (1<<10) /* Bit 10:      Link Partner can HD */
+                                                                       /* Bit  9..8:   reserved */
+#define PHY_B_1000S_IEC                0xff    /* Bit  7..0:   Idle Error Count */
+
+/*****  PHY_BCOM_EXT_STAT      16 bit r/o      Extended Status Register *****/
+#define PHY_B_ES_X_FD_CAP      (1<<15) /* Bit 15:      1000Base-X FD capable */
+#define PHY_B_ES_X_HD_CAP      (1<<14) /* Bit 14:      1000Base-X HD capable */
+#define PHY_B_ES_T_FD_CAP      (1<<13) /* Bit 13:      1000Base-T FD capable */
+#define PHY_B_ES_T_HD_CAP      (1<<12) /* Bit 12:      1000Base-T HD capable */
+                                                                       /* Bit 11..0:   reserved */
+
+/*****  PHY_BCOM_P_EXT_CTRL    16 bit r/w      PHY Extended Control Reg *****/
+#define PHY_B_PEC_MAC_PHY      (1<<15) /* Bit 15:      10BIT/GMI-Interface */
+#define PHY_B_PEC_DIS_CROSS    (1<<14) /* Bit 14:      Disable MDI Crossover */
+#define PHY_B_PEC_TX_DIS       (1<<13) /* Bit 13:      Tx output Disabled */
+#define PHY_B_PEC_INT_DIS      (1<<12) /* Bit 12:      Interrupts Disabled */
+#define PHY_B_PEC_F_INT                (1<<11) /* Bit 11:      Force Interrupt */
+#define PHY_B_PEC_BY_45                (1<<10) /* Bit 10:      Bypass 4B5B-Decoder */
+#define PHY_B_PEC_BY_SCR       (1<<9)  /* Bit  9:      Bypass Scrambler */
+#define PHY_B_PEC_BY_MLT3      (1<<8)  /* Bit  8:      Bypass MLT3 Encoder */
+#define PHY_B_PEC_BY_RXA       (1<<7)  /* Bit  7:      Bypass Rx Alignm. */
+#define PHY_B_PEC_RES_SCR      (1<<6)  /* Bit  6:      Reset Scrambler */
+#define PHY_B_PEC_EN_LTR       (1<<5)  /* Bit  5:      Ena LED Traffic Mode */
+#define PHY_B_PEC_LED_ON       (1<<4)  /* Bit  4:      Force LED's on */
+#define PHY_B_PEC_LED_OFF      (1<<3)  /* Bit  3:      Force LED's off */
+#define PHY_B_PEC_EX_IPG       (1<<2)  /* Bit  2:      Extend Tx IPG Mode */
+#define PHY_B_PEC_3_LED                (1<<1)  /* Bit  1:      Three Link LED mode */
+#define PHY_B_PEC_HIGH_LA      (1<<0)  /* Bit  0:      GMII FIFO Elasticy */
+
+/*****  PHY_BCOM_P_EXT_STAT    16 bit r/o      PHY Extended Status Reg *****/
+                                                                       /* Bit 15..14:  reserved */
+#define PHY_B_PES_CROSS_STAT   (1<<13) /* Bit 13:      MDI Crossover Status */
+#define PHY_B_PES_INT_STAT     (1<<12) /* Bit 12:      Interrupt Status */
+#define PHY_B_PES_RRS          (1<<11) /* Bit 11:      Remote Receiver Stat. */
+#define PHY_B_PES_LRS          (1<<10) /* Bit 10:      Local Receiver Stat. */
+#define PHY_B_PES_LOCKED       (1<<9)  /* Bit  9:      Locked */
+#define PHY_B_PES_LS           (1<<8)  /* Bit  8:      Link Status */
+#define PHY_B_PES_RF           (1<<7)  /* Bit  7:      Remote Fault */
+#define PHY_B_PES_CE_ER                (1<<6)  /* Bit  6:      Carrier Ext Error */
+#define PHY_B_PES_BAD_SSD      (1<<5)  /* Bit  5:      Bad SSD */
+#define PHY_B_PES_BAD_ESD      (1<<4)  /* Bit  4:      Bad ESD */
+#define PHY_B_PES_RX_ER                (1<<3)  /* Bit  3:      Receive Error */
+#define PHY_B_PES_TX_ER                (1<<2)  /* Bit  2:      Transmit Error */
+#define PHY_B_PES_LOCK_ER      (1<<1)  /* Bit  1:      Lock Error */
+#define PHY_B_PES_MLT3_ER      (1<<0)  /* Bit  0:      MLT3 code Error */
+
+/*****  PHY_BCOM_FC_CTR                16 bit r/w      False Carrier Counter *****/
+                                                                       /* Bit 15..8:   reserved */
+#define PHY_B_FC_CTR           0xff    /* Bit  7..0:   False Carrier Counter */
+
+/*****  PHY_BCOM_RNO_CTR       16 bit r/w      Receive NOT_OK Counter *****/
+#define PHY_B_RC_LOC_MSK       0xff00  /* Bit 15..8:   Local Rx NOT_OK cnt */
+#define PHY_B_RC_REM_MSK       0x00ff  /* Bit  7..0:   Remote Rx NOT_OK cnt */
+
+/*****  PHY_BCOM_AUX_CTRL      16 bit r/w      Auxiliary Control Reg *****/
+#define PHY_B_AC_L_SQE         (1<<15) /* Bit 15:      Low Squelch */
+#define PHY_B_AC_LONG_PACK     (1<<14) /* Bit 14:      Rx Long Packets */
+#define PHY_B_AC_ER_CTRL       (3<<12) /* Bit 13..12:  Edgerate Control */
+                                                                       /* Bit 11:      reserved */
+#define PHY_B_AC_TX_TST                (1<<10) /* Bit 10:      Tx test bit, always 1 */
+                                                                       /* Bit  9.. 8:  reserved */
+#define PHY_B_AC_DIS_PRF       (1<<7)  /* Bit  7:      dis part resp filter */
+                                                                       /* Bit  6:      reserved */
+#define PHY_B_AC_DIS_PM                (1<<5)  /* Bit  5:      dis power management */
+                                                                       /* Bit  4:      reserved */
+#define PHY_B_AC_DIAG          (1<<3)  /* Bit  3:      Diagnostic Mode */
+                                                                       /* Bit  2.. 0:  reserved */
+
+/*****  PHY_BCOM_AUX_STAT      16 bit r/o      Auxiliary Status Reg *****/
+#define PHY_B_AS_AN_C          (1<<15) /* Bit 15:      AutoNeg complete */
+#define PHY_B_AS_AN_CA         (1<<14) /* Bit 14:      AN Complete Ack */
+#define PHY_B_AS_ANACK_D       (1<<13) /* Bit 13:      AN Ack Detect */
+#define PHY_B_AS_ANAB_D                (1<<12) /* Bit 12:      AN Ability Detect */
+#define PHY_B_AS_NPW           (1<<11) /* Bit 11:      AN Next Page Wait */
+#define PHY_B_AS_AN_RES_MSK    (7<<8)  /* Bit 10..8:   AN HDC */
+#define PHY_B_AS_PDF           (1<<7)  /* Bit  7:      Parallel Detect. Fault */
+#define PHY_B_AS_RF                    (1<<6)  /* Bit  6:      Remote Fault */
+#define PHY_B_AS_ANP_R         (1<<5)  /* Bit  5:      AN Page Received */
+#define PHY_B_AS_LP_ANAB       (1<<4)  /* Bit  4:      LP AN Ability */
+#define PHY_B_AS_LP_NPAB       (1<<3)  /* Bit  3:      LP Next Page Ability */
+#define PHY_B_AS_LS                    (1<<2)  /* Bit  2:      Link Status */
+#define PHY_B_AS_PRR           (1<<1)  /* Bit  1:      Pause Resolution-Rx */
+#define PHY_B_AS_PRT           (1<<0)  /* Bit  0:      Pause Resolution-Tx */
+
+#define PHY_B_AS_PAUSE_MSK     (PHY_B_AS_PRR | PHY_B_AS_PRT)
+
+/*****  PHY_BCOM_INT_STAT      16 bit r/o      Interrupt Status Reg *****/
+/*****  PHY_BCOM_INT_MASK      16 bit r/w      Interrupt Mask Reg *****/
+                                                                       /* Bit 15:      reserved */
+#define PHY_B_IS_PSE           (1<<14) /* Bit 14:      Pair Swap Error */
+#define PHY_B_IS_MDXI_SC       (1<<13) /* Bit 13:      MDIX Status Change */
+#define PHY_B_IS_HCT           (1<<12) /* Bit 12:      counter above 32k */
+#define PHY_B_IS_LCT           (1<<11) /* Bit 11:      counter above 128 */
+#define PHY_B_IS_AN_PR         (1<<10) /* Bit 10:      Page Received */
+#define PHY_B_IS_NO_HDCL       (1<<9)  /* Bit  9:      No HCD Link */
+#define PHY_B_IS_NO_HDC                (1<<8)  /* Bit  8:      No HCD */
+#define PHY_B_IS_NEG_USHDC     (1<<7)  /* Bit  7:      Negotiated Unsup. HCD */
+#define PHY_B_IS_SCR_S_ER      (1<<6)  /* Bit  6:      Scrambler Sync Error */
+#define PHY_B_IS_RRS_CHANGE    (1<<5)  /* Bit  5:      Remote Rx Stat Change */
+#define PHY_B_IS_LRS_CHANGE    (1<<4)  /* Bit  4:      Local Rx Stat Change */
+#define PHY_B_IS_DUP_CHANGE    (1<<3)  /* Bit  3:      Duplex Mode Change */
+#define PHY_B_IS_LSP_CHANGE    (1<<2)  /* Bit  2:      Link Speed Change */
+#define PHY_B_IS_LST_CHANGE    (1<<1)  /* Bit  1:      Link Status Changed */
+#define PHY_B_IS_CRC_ER                (1<<0)  /* Bit  0:      CRC Error */
+
+#define PHY_B_DEF_MSK  (~(PHY_B_IS_AN_PR | PHY_B_IS_LST_CHANGE))
+
+/* Pause Bits (PHY_B_AN_ASP and PHY_B_AN_PC) encoding */
+#define PHY_B_P_NO_PAUSE       (0<<10) /* Bit 11..10:  no Pause Mode */
+#define PHY_B_P_SYM_MD         (1<<10) /* Bit 11..10:  symmetric Pause Mode */
+#define PHY_B_P_ASYM_MD                (2<<10) /* Bit 11..10:  asymmetric Pause Mode */
+#define PHY_B_P_BOTH_MD                (3<<10) /* Bit 11..10:  both Pause Mode */
+
+/*
+ * Resolved Duplex mode and Capabilities (Aux Status Summary Reg)
+ */
+#define PHY_B_RES_1000FD       (7<<8)  /* Bit 10..8:   1000Base-T Full Dup. */
+#define PHY_B_RES_1000HD       (6<<8)  /* Bit 10..8:   1000Base-T Half Dup. */
+/* others: 100/10: invalid for us */
+
+/*
+ * Level One-Specific
+ */
+/*****  PHY_LONE_1000T_CTRL    16 bit r/w      1000Base-T Control Reg *****/
+#define PHY_L_1000C_TEST       (7<<13) /* Bit 15..13:  Test Modes */
+#define PHY_L_1000C_MSE                (1<<12) /* Bit 12:      Master/Slave Enable */
+#define PHY_L_1000C_MSC                (1<<11) /* Bit 11:      M/S Configuration */
+#define PHY_L_1000C_RD         (1<<10) /* Bit 10:      Repeater/DTE */
+#define PHY_L_1000C_AFD                (1<<9)  /* Bit  9:      Advertise Full Duplex */
+#define PHY_L_1000C_AHD                (1<<8)  /* Bit  8:      Advertise Half Duplex */
+                                                                       /* Bit  7..0:   reserved */
+
+/*****  PHY_LONE_1000T_STAT    16 bit r/o      1000Base-T Status Reg *****/
+#define PHY_L_1000S_MSF                (1<<15) /* Bit 15:      Master/Slave Fault */
+#define PHY_L_1000S_MSR                (1<<14) /* Bit 14:      Master/Slave Result */
+#define PHY_L_1000S_LRS                (1<<13) /* Bit 13:      Local Receiver Status */
+#define PHY_L_1000S_RRS                (1<<12) /* Bit 12:      Remote Receiver Status */
+#define PHY_L_1000S_LP_FD      (1<<11) /* Bit 11:      Link Partner can FD */
+#define PHY_L_1000S_LP_HD      (1<<10) /* Bit 10:      Link Partner can HD */
+                                                                       /* Bit  9..8:   reserved */
+#define PHY_B_1000S_IEC                0xff    /* Bit  7..0:   Idle Error Count */
+
+/*****  PHY_LONE_EXT_STAT      16 bit r/o      Extended Status Register *****/
+#define PHY_L_ES_X_FD_CAP      (1<<15) /* Bit 15:      1000Base-X FD capable */
+#define PHY_L_ES_X_HD_CAP      (1<<14) /* Bit 14:      1000Base-X HD capable */
+#define PHY_L_ES_T_FD_CAP      (1<<13) /* Bit 13:      1000Base-T FD capable */
+#define PHY_L_ES_T_HD_CAP      (1<<12) /* Bit 12:      1000Base-T HD capable */
+                                                                       /* Bit 11..0:   reserved */
+
+/*****  PHY_LONE_PORT_CFG      16 bit r/w      Port Configuration Reg *****/
+#define PHY_L_PC_REP_MODE      (1<<15) /* Bit 15:      Repeater Mode */
+                                                                       /* Bit 14:      reserved */
+#define PHY_L_PC_TX_DIS                (1<<13) /* Bit 13:      Tx output Disabled */
+#define PHY_L_PC_BY_SCR                (1<<12) /* Bit 12:      Bypass Scrambler */
+#define PHY_L_PC_BY_45         (1<<11) /* Bit 11:      Bypass 4B5B-Decoder */
+#define PHY_L_PC_JAB_DIS       (1<<10) /* Bit 10:      Jabber Disabled */
+#define PHY_L_PC_SQE           (1<<9)  /* Bit  9:      Enable Heartbeat */
+#define PHY_L_PC_TP_LOOP       (1<<8)  /* Bit  8:      TP Loopback */
+#define PHY_L_PC_SSS           (1<<7)  /* Bit  7:      Smart Speed Selection */
+#define PHY_L_PC_FIFO_SIZE     (1<<6)  /* Bit  6:      FIFO Size */
+#define PHY_L_PC_PRE_EN                (1<<5)  /* Bit  5:      Preamble Enable */
+#define PHY_L_PC_CIM           (1<<4)  /* Bit  4:      Carrier Integrity Mon */
+#define PHY_L_PC_10_SER                (1<<3)  /* Bit  3:      Use Serial Output */
+#define PHY_L_PC_ANISOL                (1<<2)  /* Bit  2:      Unisolate Port */
+#define PHY_L_PC_TEN_BIT       (1<<1)  /* Bit  1:      10bit iface mode on */
+#define PHY_L_PC_ALTCLOCK      (1<<0)  /* Bit  0: (ro) ALTCLOCK Mode on */
+
+/*****  PHY_LONE_Q_STAT                16 bit r/o      Quick Status Reg *****/
+#define PHY_L_QS_D_RATE                (3<<14) /* Bit 15..14:  Data Rate */
+#define PHY_L_QS_TX_STAT       (1<<13) /* Bit 13:      Transmitting */
+#define PHY_L_QS_RX_STAT       (1<<12) /* Bit 12:      Receiving */
+#define PHY_L_QS_COL_STAT      (1<<11) /* Bit 11:      Collision */
+#define PHY_L_QS_L_STAT                (1<<10) /* Bit 10:      Link is up */
+#define PHY_L_QS_DUP_MOD       (1<<9)  /* Bit  9:      Full/Half Duplex */
+#define PHY_L_QS_AN                    (1<<8)  /* Bit  8:      AutoNeg is On */
+#define PHY_L_QS_AN_C          (1<<7)  /* Bit  7:      AN is Complete */
+#define PHY_L_QS_LLE           (7<<4)  /* Bit  6:      Line Length Estim. */
+#define PHY_L_QS_PAUSE         (1<<3)  /* Bit  3:      LP advertised Pause */
+#define PHY_L_QS_AS_PAUSE      (1<<2)  /* Bit  2:      LP adv. asym. Pause */
+#define PHY_L_QS_ISOLATE       (1<<1)  /* Bit  1:      CIM Isolated */
+#define PHY_L_QS_EVENT         (1<<0)  /* Bit  0:      Event has occurred */
+
+/*****  PHY_LONE_INT_ENAB      16 bit r/w      Interrupt Enable Reg *****/
+/*****  PHY_LONE_INT_STAT      16 bit r/o      Interrupt Status Reg *****/
+                                                                       /* Bit 15..14:  reserved */
+#define PHY_L_IS_AN_F          (1<<13) /* Bit 13:      Auto-Negotiation fault */
+                                                                       /* Bit 12:      not described */
+#define PHY_L_IS_CROSS         (1<<11) /* Bit 11:      Crossover used */
+#define PHY_L_IS_POL           (1<<10) /* Bit 10:      Polarity correct. used */
+#define PHY_L_IS_SS                    (1<<9)  /* Bit  9:      Smart Speed Downgrade */
+#define PHY_L_IS_CFULL         (1<<8)  /* Bit  8:      Counter Full */
+#define PHY_L_IS_AN_C          (1<<7)  /* Bit  7:      AutoNeg Complete */
+#define PHY_L_IS_SPEED         (1<<6)  /* Bit  6:      Speed Changed */
+#define PHY_L_IS_DUP           (1<<5)  /* Bit  5:      Duplex Changed */
+#define PHY_L_IS_LS                    (1<<4)  /* Bit  4:      Link Status Changed */
+#define PHY_L_IS_ISOL          (1<<3)  /* Bit  3:      Isolate Occured */
+#define PHY_L_IS_MDINT         (1<<2)  /* Bit  2: (ro) STAT: MII Int Pending */
+#define PHY_L_IS_INTEN         (1<<1)  /* Bit  1:      ENAB: Enable IRQs */
+#define PHY_L_IS_FORCE         (1<<0)  /* Bit  0:      ENAB: Force Interrupt */
+
+/* int. mask */
+#define PHY_L_DEF_MSK          (PHY_L_IS_LS | PHY_L_IS_ISOL | PHY_L_IS_INTEN)
+
+/*****  PHY_LONE_LED_CFG       16 bit r/w      LED Configuration Reg *****/
+#define PHY_L_LC_LEDC          (3<<14) /* Bit 15..14:  Col/Blink/On/Off */
+#define PHY_L_LC_LEDR          (3<<12) /* Bit 13..12:  Rx/Blink/On/Off */
+#define PHY_L_LC_LEDT          (3<<10) /* Bit 11..10:  Tx/Blink/On/Off */
+#define PHY_L_LC_LEDG          (3<<8)  /* Bit  9..8:   Giga/Blink/On/Off */
+#define PHY_L_LC_LEDS          (3<<6)  /* Bit  7..6:   10-100/Blink/On/Off */
+#define PHY_L_LC_LEDL          (3<<4)  /* Bit  5..4:   Link/Blink/On/Off */
+#define PHY_L_LC_LEDF          (3<<2)  /* Bit  3..2:   Duplex/Blink/On/Off */
+#define PHY_L_LC_PSTRECH       (1<<1)  /* Bit  1:      Strech LED Pulses */
+#define PHY_L_LC_FREQ          (1<<0)  /* Bit  0:      30/100 ms */
+
+/*****  PHY_LONE_PORT_CTRL     16 bit r/w      Port Control Reg *****/
+#define PHY_L_PC_TX_TCLK       (1<<15) /* Bit 15:      Enable TX_TCLK */
+                                                                       /* Bit 14:      reserved */
+#define PHY_L_PC_ALT_NP                (1<<13) /* Bit 14:      Alternate Next Page */
+#define PHY_L_PC_GMII_ALT      (1<<12) /* Bit 13:      Alternate GMII driver */
+                                                                       /* Bit 11:      reserved */
+#define PHY_L_PC_TEN_CRS       (1<<10) /* Bit 10:      Extend CRS*/
+                                                                       /* Bit  9..0:   not described */
+
+/*****  PHY_LONE_CIM           16 bit r/o      CIM Reg *****/
+#define PHY_L_CIM_ISOL         (255<<8)/* Bit 15..8:   Isolate Count */
+#define PHY_L_CIM_FALSE_CAR    (255<<0)/* Bit  7..0:   False Carrier Count */
+
+
+/*
+ * Pause Bits (PHY_L_AN_ASP and PHY_L_AN_PC) encoding
+ */
+#define PHY_L_P_NO_PAUSE       (0<<10) /* Bit 11..10:  no Pause Mode */
+#define PHY_L_P_SYM_MD         (1<<10) /* Bit 11..10:  symmetric Pause Mode */
+#define PHY_L_P_ASYM_MD                (2<<10) /* Bit 11..10:  asymmetric Pause Mode */
+#define PHY_L_P_BOTH_MD                (3<<10) /* Bit 11..10:  both Pause Mode */
+
+
+/*
+ * National-Specific
+ */
+/*****  PHY_NAT_1000T_CTRL     16 bit r/w      1000Base-T Control Reg *****/
+#define PHY_N_1000C_TEST       (7<<13) /* Bit 15..13:  Test Modes */
+#define PHY_N_1000C_MSE                (1<<12) /* Bit 12:      Master/Slave Enable */
+#define PHY_N_1000C_MSC                (1<<11) /* Bit 11:      M/S Configuration */
+#define PHY_N_1000C_RD         (1<<10) /* Bit 10:      Repeater/DTE */
+#define PHY_N_1000C_AFD                (1<<9)  /* Bit  9:      Advertise Full Duplex */
+#define PHY_N_1000C_AHD                (1<<8)  /* Bit  8:      Advertise Half Duplex */
+#define PHY_N_1000C_APC                (1<<7)  /* Bit  7:      Asymmetric Pause Cap. */
+                                                                       /* Bit  6..0:   reserved */
+
+/*****  PHY_NAT_1000T_STAT     16 bit r/o      1000Base-T Status Reg *****/
+#define PHY_N_1000S_MSF                (1<<15) /* Bit 15:      Master/Slave Fault */
+#define PHY_N_1000S_MSR                (1<<14) /* Bit 14:      Master/Slave Result */
+#define PHY_N_1000S_LRS                (1<<13) /* Bit 13:      Local Receiver Status */
+#define PHY_N_1000S_RRS                (1<<12) /* Bit 12:      Remote Receiver Status*/
+#define PHY_N_1000S_LP_FD      (1<<11) /* Bit 11:      Link Partner can FD */
+#define PHY_N_1000S_LP_HD      (1<<10) /* Bit 10:      Link Partner can HD */
+#define PHY_N_1000C_LP_APC     (1<<9)  /* Bit  9:      LP Asym. Pause Cap. */
+                                                                       /* Bit  8:      reserved */
+#define PHY_N_1000S_IEC                0xff    /* Bit  7..0:   Idle Error Count */
+
+/*****  PHY_NAT_EXT_STAT       16 bit r/o      Extended Status Register *****/
+#define PHY_N_ES_X_FD_CAP      (1<<15) /* Bit 15:      1000Base-X FD capable */
+#define PHY_N_ES_X_HD_CAP      (1<<14) /* Bit 14:      1000Base-X HD capable */
+#define PHY_N_ES_T_FD_CAP      (1<<13) /* Bit 13:      1000Base-T FD capable */
+#define PHY_N_ES_T_HD_CAP      (1<<12) /* Bit 12:      1000Base-T HD capable */
+                                                                       /* Bit 11..0:   reserved */
+
+/* todo: those are still missing */
+/*****  PHY_NAT_EXT_CTRL1      16 bit r/o      Extended Control Reg1 *****/
+/*****  PHY_NAT_Q_STAT1                16 bit r/o      Quick Status Reg1 *****/
+/*****  PHY_NAT_10B_OP         16 bit r/o      10Base-T Operations Reg *****/
+/*****  PHY_NAT_EXT_CTRL2      16 bit r/o      Extended Control Reg1 *****/
+/*****  PHY_NAT_Q_STAT2                16 bit r/o      Quick Status Reg2 *****/
+/*****  PHY_NAT_PHY_ADDR       16 bit r/o      PHY Address Register *****/
+
+/*
+ * Marvell-Specific
+ */
+/*****  PHY_MARV_AUNE_ADV      16 bit r/w      Auto-Negotiation Advertisement *****/
+/*****  PHY_MARV_AUNE_LP       16 bit r/w      Link Part Ability Reg *****/
+#define PHY_M_AN_NXT_PG                BIT_15  /* Request Next Page */
+#define PHY_M_AN_ACK           BIT_14  /* (ro) Acknowledge Received */
+#define PHY_M_AN_RF                    BIT_13  /* Remote Fault */
+                                                                       /* Bit 12:      reserved */
+#define PHY_M_AN_ASP           BIT_11  /* Asymmetric Pause */
+#define PHY_M_AN_PC                    BIT_10  /* MAC Pause implemented */
+#define PHY_M_AN_100_FD                BIT_8   /* Advertise 100Base-TX Full Duplex */
+#define PHY_M_AN_100_HD                BIT_7   /* Advertise 100Base-TX Half Duplex */
+#define PHY_M_AN_10_FD         BIT_6   /* Advertise 10Base-TX Full Duplex */
+#define PHY_M_AN_10_HD         BIT_5   /* Advertise 10Base-TX Half Duplex */
+
+/* special defines for FIBER (88E1011S only) */
+#define PHY_M_AN_ASP_X         BIT_8   /* Asymmetric Pause */
+#define PHY_M_AN_PC_X          BIT_7   /* MAC Pause implemented */
+#define PHY_M_AN_1000X_AHD     BIT_6   /* Advertise 10000Base-X Half Duplex */
+#define PHY_M_AN_1000X_AFD     BIT_5   /* Advertise 10000Base-X Full Duplex */
+
+/* Pause Bits (PHY_M_AN_ASP_X and PHY_M_AN_PC_X) encoding */
+#define PHY_M_P_NO_PAUSE_X     (0<<7)  /* Bit  8.. 7:  no Pause Mode */
+#define PHY_M_P_SYM_MD_X       (1<<7)  /* Bit  8.. 7:  symmetric Pause Mode */
+#define PHY_M_P_ASYM_MD_X      (2<<7)  /* Bit  8.. 7:  asymmetric Pause Mode */
+#define PHY_M_P_BOTH_MD_X      (3<<7)  /* Bit  8.. 7:  both Pause Mode */
+
+/*****  PHY_MARV_1000T_CTRL    16 bit r/w      1000Base-T Control Reg *****/
+#define PHY_M_1000C_TEST       (7<<13) /* Bit 15..13:  Test Modes */
+#define PHY_M_1000C_MSE                (1<<12) /* Bit 12:      Manual Master/Slave Enable */
+#define PHY_M_1000C_MSC                (1<<11) /* Bit 11:      M/S Configuration (1=Master) */
+#define PHY_M_1000C_MPD                (1<<10) /* Bit 10:      Multi-Port Device */
+#define PHY_M_1000C_AFD                (1<<9)  /* Bit  9:      Advertise Full Duplex */
+#define PHY_M_1000C_AHD                (1<<8)  /* Bit  8:      Advertise Half Duplex */
+                                                                       /* Bit  7..0:   reserved */
+
+/*****  PHY_MARV_PHY_CTRL      16 bit r/w      PHY Specific Ctrl Reg *****/
+#define PHY_M_PC_TX_FFD_MSK    (3<<14) /* Bit 15..14:  Tx FIFO Depth Mask */
+#define PHY_M_PC_RX_FFD_MSK    (3<<12) /* Bit 13..12:  Rx FIFO Depth Mask */
+#define PHY_M_PC_ASS_CRS_TX    (1<<11) /* Bit 11:      Assert CRS on Transmit */
+#define PHY_M_PC_FL_GOOD       (1<<10) /* Bit 10:      Force Link Good */
+#define PHY_M_PC_EN_DET_MSK    (3<<8)  /* Bit  9.. 8:  Energy Detect Mask */
+#define PHY_M_PC_ENA_EXT_D     (1<<7)  /* Bit  7:      Enable Ext. Distance (10BT) */
+#define PHY_M_PC_MDIX_MSK      (3<<5)  /* Bit  6.. 5:  MDI/MDIX Config. Mask */
+#define PHY_M_PC_DIS_125CLK    (1<<4)  /* Bit  4:      Disable 125 CLK */
+#define PHY_M_PC_MAC_POW_UP    (1<<3)  /* Bit  3:      MAC Power up */
+#define PHY_M_PC_SQE_T_ENA     (1<<2)  /* Bit  2:      SQE Test Enabled */
+#define PHY_M_PC_POL_R_DIS     (1<<1)  /* Bit  1:      Polarity Reversal Disabled */
+#define PHY_M_PC_DIS_JABBER    (1<<0)  /* Bit  0:      Disable Jabber */
+
+#define PHY_M_PC_EN_DET                        SHIFT8(2)       /* Energy Detect (Mode 1) */
+#define PHY_M_PC_EN_DET_PLUS   SHIFT8(3)       /* Energy Detect Plus (Mode 2) */
+
+#define PHY_M_PC_MDI_XMODE(x)  SHIFT5(x)       
+#define PHY_M_PC_MAN_MDI       0       /* 00 = Manual MDI configuration */
+#define PHY_M_PC_MAN_MDIX      1               /* 01 = Manual MDIX configuration */
+#define PHY_M_PC_ENA_AUTO      3               /* 11 = Enable Automatic Crossover */
+
+/*****  PHY_MARV_PHY_STAT      16 bit r/o      PHY Specific Status Reg *****/
+#define PHY_M_PS_SPEED_MSK     (3<<14) /* Bit 15..14:  Speed Mask */
+#define PHY_M_PS_SPEED_1000    (1<<15) /*       10 = 1000 Mbps */
+#define PHY_M_PS_SPEED_100     (1<<14) /*       01 =  100 Mbps */
+#define PHY_M_PS_SPEED_10      0               /*       00 =   10 Mbps */
+#define PHY_M_PS_FULL_DUP      (1<<13) /* Bit 13:      Full Duplex */
+#define PHY_M_PS_PAGE_REC      (1<<12) /* Bit 12:      Page Received */
+#define PHY_M_PS_SPDUP_RES     (1<<11) /* Bit 11:      Speed & Duplex Resolved */
+#define PHY_M_PS_LINK_UP       (1<<10) /* Bit 10:      Link Up */
+#define PHY_M_PS_CABLE_MSK     (3<<7)  /* Bit  9.. 7:  Cable Length Mask */
+#define PHY_M_PS_MDI_X_STAT    (1<<6)  /* Bit  6:      MDI Crossover Stat (1=MDIX) */
+#define PHY_M_PS_DOWNS_STAT    (1<<5)  /* Bit  5:      Downshift Status (1=downsh.) */
+#define PHY_M_PS_ENDET_STAT    (1<<4)  /* Bit  4:      Energy Detect Status (1=act) */
+#define PHY_M_PS_TX_P_EN       (1<<3)  /* Bit  3:      Tx Pause Enabled */
+#define PHY_M_PS_RX_P_EN       (1<<2)  /* Bit  2:      Rx Pause Enabled */
+#define PHY_M_PS_POL_REV       (1<<1)  /* Bit  1:      Polarity Reversed */
+#define PHY_M_PC_JABBER                (1<<0)  /* Bit  0:      Jabber */
+
+#define PHY_M_PS_PAUSE_MSK     (PHY_M_PS_TX_P_EN | PHY_M_PS_RX_P_EN)
+
+/*****  PHY_MARV_INT_MASK      16 bit r/w      Interrupt Mask Reg *****/
+/*****  PHY_MARV_INT_STAT      16 bit r/o      Interrupt Status Reg *****/
+#define PHY_M_IS_AN_ERROR      (1<<15) /* Bit 15:      Auto-Negotiation Error */
+#define PHY_M_IS_LSP_CHANGE    (1<<14) /* Bit 14:      Link Speed Changed */
+#define PHY_M_IS_DUP_CHANGE    (1<<13) /* Bit 13:      Duplex Mode Changed */
+#define PHY_M_IS_AN_PR         (1<<12) /* Bit 12:      Page Received */
+#define PHY_M_IS_AN_COMPL      (1<<11) /* Bit 11:      Auto-Negotiation Completed */
+#define PHY_M_IS_LST_CHANGE    (1<<10) /* Bit 10:      Link Status Changed */
+#define PHY_M_IS_SYMB_ERROR    (1<<9)  /* Bit  9:      Symbol Error */
+#define PHY_M_IS_FALSE_CARR    (1<<8)  /* Bit  8:      False Carrier */
+#define PHY_M_IS_FIFO_ERROR    (1<<7)  /* Bit  7:      FIFO Overflow/Underrun Error */
+#define PHY_M_IS_MDI_CHANGE    (1<<6)  /* Bit  6:      MDI Crossover Changed */
+#define PHY_M_IS_DOWNSH_DET    (1<<5)  /* Bit  5:      Downshift Detected */
+#define PHY_M_IS_END_CHANGE    (1<<4)  /* Bit  4:      Energy Detect Changed */
+                                                                       /* Bit  3..2:   reserved */
+#define PHY_M_IS_POL_CHANGE    (1<<1)  /* Bit  1:      Polarity Changed */
+#define PHY_M_IS_JABBER                (1<<0)  /* Bit  0:      Jabber */
+
+#define PHY_M_DEF_MSK          (PHY_M_IS_AN_ERROR | PHY_M_IS_AN_PR | \
+                                                       PHY_M_IS_LST_CHANGE | PHY_M_IS_FIFO_ERROR)
+
+/*****  PHY_MARV_EXT_CTRL      16 bit r/w      Ext. PHY Specific Ctrl *****/
+#define PHY_M_EC_M_DSC_MSK     (3<<10) /* Bit 11..10:  Master downshift counter */
+#define PHY_M_EC_S_DSC_MSK     (3<<8)  /* Bit  9.. 8:  Slave  downshift counter */
+#define PHY_M_EC_MAC_S_MSK     (7<<4)  /* Bit  6.. 4:  Def. MAC interface speed */
+#define PHY_M_EC_FIB_AN_ENA    (1<<3)  /* Bit  3:      Fiber Auto-Neg. Enable */
+
+#define PHY_M_EC_M_DSC(x)              SHIFT10(x)      /* 00=1x; 01=2x; 10=3x; 11=4x */
+#define PHY_M_EC_S_DSC(x)              SHIFT8(x)       /* 00=dis; 01=1x; 10=2x; 11=3x */
+#define PHY_M_EC_MAC_S(x)              SHIFT4(x)       /* 01X=0; 110=2.5; 111=25 (MHz) */
+
+#define MAC_TX_CLK_0_MHZ       2
+#define MAC_TX_CLK_2_5_MHZ     6
+#define MAC_TX_CLK_25_MHZ      7
+
+/*****  PHY_MARV_LED_CTRL      16 bit r/w      LED Control Reg *****/
+#define PHY_M_LEDC_DIS_LED     (1<<15) /* Bit 15:      Disable LED */
+#define PHY_M_LEDC_PULS_MSK    (7<<12) /* Bit 14..12:  Pulse Stretch Mask */
+#define PHY_M_LEDC_F_INT       (1<<11) /* Bit 11:      Force Interrupt */
+#define PHY_M_LEDC_BL_R_MSK    (7<<8)  /* Bit 10.. 8:  Blink Rate Mask */
+                                                                       /* Bit  7.. 5:  reserved */
+#define PHY_M_LEDC_LINK_MSK    (3<<3)  /* Bit  4.. 3:  Link Control Mask */
+#define PHY_M_LEDC_DP_CTRL     (1<<2)  /* Bit  2:      Duplex Control */
+#define PHY_M_LEDC_RX_CTRL     (1<<1)  /* Bit  1:      Rx activity / Link */
+#define PHY_M_LEDC_TX_CTRL     (1<<0)  /* Bit  0:      Tx activity / Link */
+
+#define PHY_M_LED_PULS_DUR(x)  SHIFT12(x)      /* Pulse Stretch Duration */
+
+#define        PULS_NO_STR             0               /* no pulse stretching */
+#define        PULS_21MS               1               /* 21 ms to 42 ms */
+#define PULS_42MS              2               /* 42 ms to 84 ms */
+#define PULS_84MS              3               /* 84 ms to 170 ms */
+#define PULS_170MS             4               /* 170 ms to 340 ms */
+#define PULS_340MS             5               /* 340 ms to 670 ms */
+#define PULS_670MS             6               /* 670 ms to 1.3 s */
+#define PULS_1300MS            7               /* 1.3 s to 2.7 s */
+
+#define PHY_M_LED_BLINK_RT(x)  SHIFT8(x)       /* Blink Rate */
+
+#define BLINK_42MS             0               /* 42 ms */
+#define BLINK_84MS             1               /* 84 ms */
+#define BLINK_170MS            2               /* 170 ms */
+#define BLINK_340MS            3               /* 340 ms */
+#define BLINK_670MS            4               /* 670 ms */
+                                                               /* values 5 - 7: reserved */
+
+/*****  PHY_MARV_LED_OVER      16 bit r/w      Manual LED Override Reg *****/
+#define PHY_M_LED_MO_DUP(x)            SHIFT10(x)      /* Bit 11..10:  Duplex */
+#define PHY_M_LED_MO_10(x)             SHIFT8(x)       /* Bit  9.. 8:  Link 10 */
+#define PHY_M_LED_MO_100(x)            SHIFT6(x)       /* Bit  7.. 6:  Link 100 */
+#define PHY_M_LED_MO_1000(x)   SHIFT4(x)       /* Bit  5.. 4:  Link 1000 */
+#define PHY_M_LED_MO_RX(x)             SHIFT2(x)       /* Bit  3.. 2:  Rx */
+#define PHY_M_LED_MO_TX(x)             SHIFT0(x)       /* Bit  1.. 0:  Tx */
+
+#define MO_LED_NORM                    0
+#define MO_LED_BLINK           1
+#define MO_LED_OFF                     2
+#define MO_LED_ON                      3
+
+/*****  PHY_MARV_EXT_CTRL_2    16 bit r/w      Ext. PHY Specific Ctrl 2 *****/
+                                                                       /* Bit 15.. 7:  reserved */
+#define PHY_M_EC2_FI_IMPED     (1<<6)  /* Bit  6:      Fiber Input  Impedance */
+#define PHY_M_EC2_FO_IMPED     (1<<5)  /* Bit  5:      Fiber Output Impedance */
+#define PHY_M_EC2_FO_M_CLK     (1<<4)  /* Bit  4:      Fiber Mode Clock Enable */
+#define PHY_M_EC2_FO_BOOST     (1<<3)  /* Bit  3:      Fiber Output Boost */
+#define PHY_M_EC2_FO_AM_MSK    7               /* Bit  2.. 0:  Fiber Output Amplitude */
+
+/***** PHY_MARV_EXT_P_STAT 16 bit r/w  Ext. PHY Specific Status *****/
+#define PHY_M_FC_AUTO_SEL      (1<<15) /* Bit 15:      Fiber/Copper Auto Sel. dis. */
+#define PHY_M_FC_AN_REG_ACC (1<<14) /* Bit 14: Fiber/Copper Autoneg. reg acc */
+#define PHY_M_FC_RESULUTION (1<<13)    /* Bit 13:      Fiber/Copper Resulution */
+#define PHY_M_SER_IF_AN_BP  (1<<12) /* Bit 12: Ser IF autoneg. bypass enable */
+#define PHY_M_SER_IF_BP_ST     (1<<11) /* Bit 11:      Ser IF autoneg. bypass status */
+#define PHY_M_IRQ_POLARITY     (1<<10) /* Bit 10:      IRQ polarity */
+                                                                       /* Bit 9..4: reserved */
+#define PHY_M_UNDOC1           (1<< 7) /* undocumented bit !! */
+#define PHY_M_MODE_MASK                (0xf<<0)/* Bit 3..0: copy of HWCFG MODE[3:0] */
+
+
+/*****  PHY_MARV_CABLE_DIAG    16 bit r/o      Cable Diagnostic Reg *****/
+#define PHY_M_CABD_ENA_TEST    (1<<15) /* Bit 15:      Enable Test */
+#define PHY_M_CABD_STAT_MSK    (3<<13) /* Bit 14..13:  Status */
+                                                                       /* Bit 12.. 8:  reserved */
+#define PHY_M_CABD_DIST_MSK    0xff    /* Bit  7.. 0:  Distance */
+
+/* values for Cable Diagnostic Status (11=fail; 00=OK; 10=open; 01=short) */
+#define CABD_STAT_NORMAL       0
+#define CABD_STAT_SHORT                1
+#define CABD_STAT_OPEN         2
+#define CABD_STAT_FAIL         3
+
+
+/*
+ * GMAC registers
+ *
+ * The GMAC registers are 16 or 32 bits wide.
+ * The GMACs host processor interface is 16 bits wide,
+ * therefore ALL registers will be addressed with 16 bit accesses.
+ *
+ * The following macros are provided to access the GMAC registers
+ * GM_IN16(), GM_OUT16, GM_IN32(), GM_OUT32(), GM_INADR(), GM_OUTADR(),
+ * GM_INHASH(), and GM_OUTHASH().
+ * The macros are defined in SkGeHw.h.
+ *
+ * Note:       NA reg  = Network Address e.g DA, SA etc.
+ *
+ */
+
+/* Port Registers */
+#define GM_GP_STAT             0x0000          /* 16 bit r/o   General Purpose Status */
+#define GM_GP_CTRL             0x0004          /* 16 bit r/w   General Purpose Control */
+#define GM_TX_CTRL             0x0008          /* 16 bit r/w   Transmit Control Reg. */
+#define GM_RX_CTRL             0x000c          /* 16 bit r/w   Receive Control Reg. */
+#define GM_TX_FLOW_CTRL        0x0010          /* 16 bit r/w   Transmit Flow-Control */
+#define GM_TX_PARAM            0x0014          /* 16 bit r/w   Transmit Parameter Reg. */
+#define GM_SERIAL_MODE 0x0018          /* 16 bit r/w   Serial Mode Register */
+
+/* Source Address Registers */
+#define GM_SRC_ADDR_1L 0x001c          /* 16 bit r/w   Source Address 1 (low) */
+#define GM_SRC_ADDR_1M 0x0020          /* 16 bit r/w   Source Address 1 (middle) */
+#define GM_SRC_ADDR_1H 0x0024          /* 16 bit r/w   Source Address 1 (high) */
+#define GM_SRC_ADDR_2L 0x0028          /* 16 bit r/w   Source Address 2 (low) */
+#define GM_SRC_ADDR_2M 0x002c          /* 16 bit r/w   Source Address 2 (middle) */
+#define GM_SRC_ADDR_2H 0x0030          /* 16 bit r/w   Source Address 2 (high) */
+
+/* Multicast Address Hash Registers */
+#define GM_MC_ADDR_H1  0x0034          /* 16 bit r/w   Multicast Address Hash 1 */
+#define GM_MC_ADDR_H2  0x0038          /* 16 bit r/w   Multicast Address Hash 2 */
+#define GM_MC_ADDR_H3  0x003c          /* 16 bit r/w   Multicast Address Hash 3 */
+#define GM_MC_ADDR_H4  0x0040          /* 16 bit r/w   Multicast Address Hash 4 */
+
+/* Interrupt Source Registers */
+#define GM_TX_IRQ_SRC  0x0044          /* 16 bit r/o   Tx Overflow IRQ Source */
+#define GM_RX_IRQ_SRC  0x0048          /* 16 bit r/o   Rx Overflow IRQ Source */
+#define GM_TR_IRQ_SRC  0x004c          /* 16 bit r/o   Tx/Rx Over. IRQ Source */
+
+/* Interrupt Mask Registers */
+#define GM_TX_IRQ_MSK  0x0050          /* 16 bit r/w   Tx Overflow IRQ Mask */
+#define GM_RX_IRQ_MSK  0x0054          /* 16 bit r/w   Rx Overflow IRQ Mask */
+#define GM_TR_IRQ_MSK  0x0058          /* 16 bit r/w   Tx/Rx Over. IRQ Mask */
+
+/* Serial Management Interface (SMI) Registers */
+#define GM_SMI_CTRL            0x0080          /* 16 bit r/w   SMI Control Register */
+#define GM_SMI_DATA            0x0084          /* 16 bit r/w   SMI Data Register */
+#define GM_PHY_ADDR            0x0088          /* 16 bit r/w   GPHY Address Register */
+
+/* MIB Counters */
+#define GM_MIB_CNT_BASE        0x0100          /* Base Address of MIB Counters */
+#define GM_MIB_CNT_SIZE        44                      /* Number of MIB Counters */
+
+/*
+ * MIB Counters base address definitions (low word) -
+ * use offset 4 for access to high word        (32 bit r/o)
+ */
+#define GM_RXF_UC_OK \
+                       (GM_MIB_CNT_BASE + 0)   /* Unicast Frames Received OK */
+#define GM_RXF_BC_OK \
+                       (GM_MIB_CNT_BASE + 8)   /* Broadcast Frames Received OK */
+#define GM_RXF_MPAUSE \
+                       (GM_MIB_CNT_BASE + 16)  /* Pause MAC Ctrl Frames Received */
+#define GM_RXF_MC_OK \
+                       (GM_MIB_CNT_BASE + 24)  /* Multicast Frames Received OK */
+#define GM_RXF_FCS_ERR \
+                       (GM_MIB_CNT_BASE + 32)  /* Rx Frame Check Seq. Error */
+       /* GM_MIB_CNT_BASE + 40:        reserved */
+#define GM_RXO_OK_LO \
+                       (GM_MIB_CNT_BASE + 48)  /* Octets Received OK Low */
+#define GM_RXO_OK_HI \
+                       (GM_MIB_CNT_BASE + 56)  /* Octets Received OK High */
+#define GM_RXO_ERR_LO \
+                       (GM_MIB_CNT_BASE + 64)  /* Octets Received Invalid Low */
+#define GM_RXO_ERR_HI \
+                       (GM_MIB_CNT_BASE + 72)  /* Octets Received Invalid High */
+#define GM_RXF_SHT \
+                       (GM_MIB_CNT_BASE + 80)  /* Frames <64 Byte Received OK */
+#define GM_RXE_FRAG \
+                       (GM_MIB_CNT_BASE + 88)  /* Frames <64 Byte Received with FCS Err */
+#define GM_RXF_64B \
+                       (GM_MIB_CNT_BASE + 96)  /* 64 Byte Rx Frame */
+#define GM_RXF_127B \
+                       (GM_MIB_CNT_BASE + 104) /* 65-127 Byte Rx Frame */
+#define GM_RXF_255B \
+                       (GM_MIB_CNT_BASE + 112) /* 128-255 Byte Rx Frame */
+#define GM_RXF_511B \
+                       (GM_MIB_CNT_BASE + 120) /* 256-511 Byte Rx Frame */
+#define GM_RXF_1023B \
+                       (GM_MIB_CNT_BASE + 128) /* 512-1023 Byte Rx Frame */
+#define GM_RXF_1518B \
+                       (GM_MIB_CNT_BASE + 136) /* 1024-1518 Byte Rx Frame */
+#define GM_RXF_MAX_SZ \
+                       (GM_MIB_CNT_BASE + 144) /* 1519-MaxSize Byte Rx Frame */
+#define GM_RXF_LNG_ERR \
+                       (GM_MIB_CNT_BASE + 152) /* Rx Frame too Long Error */
+#define GM_RXF_JAB_PKT \
+                       (GM_MIB_CNT_BASE + 160) /* Rx Jabber Packet Frame */
+       /* GM_MIB_CNT_BASE + 168:       reserved */
+#define GM_RXE_FIFO_OV \
+                       (GM_MIB_CNT_BASE + 176) /* Rx FIFO overflow Event */
+       /* GM_MIB_CNT_BASE + 184:       reserved */
+#define GM_TXF_UC_OK \
+                       (GM_MIB_CNT_BASE + 192) /* Unicast Frames Xmitted OK */
+#define GM_TXF_BC_OK \
+                       (GM_MIB_CNT_BASE + 200) /* Broadcast Frames Xmitted OK */
+#define GM_TXF_MPAUSE \
+                       (GM_MIB_CNT_BASE + 208) /* Pause MAC Ctrl Frames Xmitted */
+#define GM_TXF_MC_OK \
+                       (GM_MIB_CNT_BASE + 216) /* Multicast Frames Xmitted OK */
+#define GM_TXO_OK_LO \
+                       (GM_MIB_CNT_BASE + 224) /* Octets Transmitted OK Low */
+#define GM_TXO_OK_HI \
+                       (GM_MIB_CNT_BASE + 232) /* Octets Transmitted OK High */
+#define GM_TXF_64B \
+                       (GM_MIB_CNT_BASE + 240) /* 64 Byte Tx Frame */
+#define GM_TXF_127B \
+                       (GM_MIB_CNT_BASE + 248) /* 65-127 Byte Tx Frame */
+#define GM_TXF_255B \
+                       (GM_MIB_CNT_BASE + 256) /* 128-255 Byte Tx Frame */
+#define GM_TXF_511B \
+                       (GM_MIB_CNT_BASE + 264) /* 256-511 Byte Tx Frame */
+#define GM_TXF_1023B \
+                       (GM_MIB_CNT_BASE + 272) /* 512-1023 Byte Tx Frame */
+#define GM_TXF_1518B \
+                       (GM_MIB_CNT_BASE + 280) /* 1024-1518 Byte Tx Frame */
+#define GM_TXF_MAX_SZ \
+                       (GM_MIB_CNT_BASE + 288) /* 1519-MaxSize Byte Tx Frame */
+       /* GM_MIB_CNT_BASE + 296:       reserved */
+#define GM_TXF_COL \
+                       (GM_MIB_CNT_BASE + 304) /* Tx Collision */
+#define GM_TXF_LAT_COL \
+                       (GM_MIB_CNT_BASE + 312) /* Tx Late Collision */
+#define GM_TXF_ABO_COL \
+                       (GM_MIB_CNT_BASE + 320) /* Tx aborted due to Exces. Col. */
+#define GM_TXF_MUL_COL \
+                       (GM_MIB_CNT_BASE + 328) /* Tx Multiple Collision */
+#define GM_TXF_SNG_COL \
+                       (GM_MIB_CNT_BASE + 336) /* Tx Single Collision */
+#define GM_TXE_FIFO_UR \
+                       (GM_MIB_CNT_BASE + 344) /* Tx FIFO Underrun Event */
+
+/*----------------------------------------------------------------------------*/
+/*
+ * GMAC Bit Definitions
+ *
+ * If the bit access behaviour differs from the register access behaviour
+ * (r/w, r/o) this is documented after the bit number.
+ * The following bit access behaviours are used:
+ *     (sc)    self clearing
+ *     (r/o)   read only
+ */
+
+/*     GM_GP_STAT      16 bit r/o      General Purpose Status Register */
+#define GM_GPSR_SPEED          (1<<15) /* Bit 15:      Port Speed (1 = 100 Mbps) */
+#define GM_GPSR_DUPLEX         (1<<14) /* Bit 14:      Duplex Mode (1 = Full) */
+#define GM_GPSR_FC_TX_DIS      (1<<13) /* Bit 13:      Tx Flow-Control Mode Disabled */
+#define GM_GPSR_LINK_UP                (1<<12) /* Bit 12:      Link Up Status */
+#define GM_GPSR_PAUSE          (1<<11) /* Bit 11:      Pause State */
+#define GM_GPSR_TX_ACTIVE      (1<<10) /* Bit 10:      Tx in Progress */
+#define GM_GPSR_EXC_COL                (1<<9)  /* Bit  9:      Excessive Collisions Occured */
+#define GM_GPSR_LAT_COL                (1<<8)  /* Bit  8:      Late Collisions Occured */
+                                                               /* Bit  7..6:   reserved */
+#define GM_GPSR_PHY_ST_CH      (1<<5)  /* Bit  5:      PHY Status Change */
+#define GM_GPSR_GIG_SPEED      (1<<4)  /* Bit  4:      Gigabit Speed (1 = 1000 Mbps) */
+#define GM_GPSR_PART_MODE      (1<<3)  /* Bit  3:      Partition mode */
+#define GM_GPSR_FC_RX_DIS      (1<<2)  /* Bit  2:      Rx Flow-Control Mode Disabled */
+#define GM_GPSR_PROM_EN                (1<<1)  /* Bit  1:      Promiscuous Mode Enabled */
+                                                               /* Bit  0:      reserved */
+       
+/*     GM_GP_CTRL      16 bit r/w      General Purpose Control Register */
+                                                               /* Bit 15:      reserved */
+#define GM_GPCR_PROM_ENA       (1<<14) /* Bit 14:      Enable Promiscuous Mode */
+#define GM_GPCR_FC_TX_DIS      (1<<13) /* Bit 13:      Disable Tx Flow-Control Mode */
+#define GM_GPCR_TX_ENA         (1<<12) /* Bit 12:      Enable Transmit */
+#define GM_GPCR_RX_ENA         (1<<11) /* Bit 11:      Enable Receive */
+#define GM_GPCR_BURST_ENA      (1<<10) /* Bit 10:      Enable Burst Mode */
+#define GM_GPCR_LOOP_ENA       (1<<9)  /* Bit  9:      Enable MAC Loopback Mode */
+#define GM_GPCR_PART_ENA       (1<<8)  /* Bit  8:      Enable Partition Mode */
+#define GM_GPCR_GIGS_ENA       (1<<7)  /* Bit  7:      Gigabit Speed (1000 Mbps) */
+#define GM_GPCR_FL_PASS                (1<<6)  /* Bit  6:      Force Link Pass */
+#define GM_GPCR_DUP_FULL       (1<<5)  /* Bit  5:      Full Duplex Mode */
+#define GM_GPCR_FC_RX_DIS      (1<<4)  /* Bit  4:      Disable Rx Flow-Control Mode */
+#define GM_GPCR_SPEED_100      (1<<3)  /* Bit  3:      Port Speed 100 Mbps */
+#define GM_GPCR_AU_DUP_DIS     (1<<2)  /* Bit  2:      Disable Auto-Update Duplex */
+#define GM_GPCR_AU_FCT_DIS     (1<<1)  /* Bit  1:      Disable Auto-Update Flow-C. */
+#define GM_GPCR_AU_SPD_DIS     (1<<0)  /* Bit  0:      Disable Auto-Update Speed */
+
+#define GM_GPCR_SPEED_1000     (GM_GPCR_GIGS_ENA | GM_GPCR_SPEED_100)
+#define GM_GPCR_AU_ALL_DIS     (GM_GPCR_AU_DUP_DIS | GM_GPCR_AU_FCT_DIS |\
+                                                        GM_GPCR_AU_SPD_DIS)
+       
+/*     GM_TX_CTRL                              16 bit r/w      Transmit Control Register */
+#define GM_TXCR_FORCE_JAM      (1<<15) /* Bit 15:      Force Jam / Flow-Control */
+#define GM_TXCR_CRC_DIS                (1<<14) /* Bit 14:      Disable insertion of CRC */
+#define GM_TXCR_PAD_DIS                (1<<13) /* Bit 13:      Disable padding of packets */
+#define GM_TXCR_COL_THR_MSK    (7<<10) /* Bit 12..10:  Collision Threshold */
+
+#define TX_COL_THR(x)          (SHIFT10(x) & GM_TXCR_COL_THR_MSK)
+
+#define TX_COL_DEF                     0x04
+       
+/*     GM_RX_CTRL                              16 bit r/w      Receive Control Register */
+#define GM_RXCR_UCF_ENA                (1<<15) /* Bit 15:      Enable Unicast filtering */
+#define GM_RXCR_MCF_ENA                (1<<14) /* Bit 14:      Enable Multicast filtering */
+#define GM_RXCR_CRC_DIS                (1<<13) /* Bit 13:      Remove 4-byte CRC */
+#define GM_RXCR_PASS_FC                (1<<12) /* Bit 12:      Pass FC packets to FIFO */
+       
+/*     GM_TX_PARAM                             16 bit r/w      Transmit Parameter Register */
+#define GM_TXPA_JAMLEN_MSK     (0x03<<14)      /* Bit 15..14:  Jam Length */
+#define GM_TXPA_JAMIPG_MSK     (0x1f<<9)       /* Bit 13..9:   Jam IPG */
+#define GM_TXPA_JAMDAT_MSK     (0x1f<<4)       /* Bit  8..4:   IPG Jam to Data */
+                                                               /* Bit  3..0:   reserved */
+
+#define TX_JAM_LEN_VAL(x)      (SHIFT14(x) & GM_TXPA_JAMLEN_MSK)
+#define TX_JAM_IPG_VAL(x)      (SHIFT9(x) & GM_TXPA_JAMIPG_MSK)
+#define TX_IPG_JAM_DATA(x)     (SHIFT4(x) & GM_TXPA_JAMDAT_MSK)
+
+#define TX_JAM_LEN_DEF         0x03
+#define TX_JAM_IPG_DEF         0x0b
+#define TX_IPG_JAM_DEF         0x1c
+
+/*     GM_SERIAL_MODE                  16 bit r/w      Serial Mode Register */
+#define GM_SMOD_DATABL_MSK     (0x1f<<11)      /* Bit 15..11:  Data Blinder (r/o) */
+#define GM_SMOD_LIMIT_4                (1<<10) /* Bit 10:      4 consecutive Tx trials */
+#define GM_SMOD_VLAN_ENA       (1<<9)  /* Bit  9:      Enable VLAN  (Max. Frame Len) */
+#define GM_SMOD_JUMBO_ENA      (1<<8)  /* Bit  8:      Enable Jumbo (Max. Frame Len) */
+                                                               /* Bit  7..5:   reserved */
+#define GM_SMOD_IPG_MSK                0x1f    /* Bit 4..0:    Inter-Packet Gap (IPG) */
+       
+#define DATA_BLIND_VAL(x)      (SHIFT11(x) & GM_SMOD_DATABL_MSK)
+#define DATA_BLIND_DEF         0x04
+
+#define IPG_DATA_VAL(x)                (x & GM_SMOD_IPG_MSK)
+#define IPG_DATA_DEF           0x1e
+
+/*     GM_SMI_CTRL                             16 bit r/w      SMI Control Register */
+#define GM_SMI_CT_PHY_A_MSK    (0x1f<<11)      /* Bit 15..11:  PHY Device Address */
+#define GM_SMI_CT_REG_A_MSK    (0x1f<<6)       /* Bit 10.. 6:  PHY Register Address */
+#define GM_SMI_CT_OP_RD                (1<<5)  /* Bit  5:      OpCode Read (0=Write)*/
+#define GM_SMI_CT_RD_VAL       (1<<4)  /* Bit  4:      Read Valid (Read completed) */
+#define GM_SMI_CT_BUSY         (1<<3)  /* Bit  3:      Busy (Operation in progress) */
+                                                               /* Bit   2..0:  reserved */
+       
+#define GM_SMI_CT_PHY_AD(x)    (SHIFT11(x) & GM_SMI_CT_PHY_A_MSK)
+#define GM_SMI_CT_REG_AD(x)    (SHIFT6(x) & GM_SMI_CT_REG_A_MSK)
+
+       /*      GM_PHY_ADDR                             16 bit r/w      GPHY Address Register */
+                                                               /* Bit  15..6:  reserved */
+#define GM_PAR_MIB_CLR         (1<<5)  /* Bit  5:      Set MIB Clear Counter Mode */
+#define GM_PAR_MIB_TST         (1<<4)  /* Bit  4:      MIB Load Counter (Test Mode) */
+                                                               /* Bit   3..0:  reserved */
+       
+/* Receive Frame Status Encoding */
+#define GMR_FS_LEN     (0xffffUL<<16)  /* Bit 31..16:  Rx Frame Length */
+                                                               /* Bit  15..14: reserved */
+#define GMR_FS_VLAN            (1L<<13)        /* Bit 13:      VLAN Packet */
+#define GMR_FS_JABBER  (1L<<12)        /* Bit 12:      Jabber Packet */
+#define GMR_FS_UN_SIZE (1L<<11)        /* Bit 11:      Undersize Packet */
+#define GMR_FS_MC              (1L<<10)        /* Bit 10:      Multicast Packet */
+#define GMR_FS_BC              (1L<<9)         /* Bit  9:      Broadcast Packet */
+#define GMR_FS_RX_OK   (1L<<8)         /* Bit  8:      Receive OK (Good Packet) */
+#define GMR_FS_GOOD_FC (1L<<7)         /* Bit  7:      Good Flow-Control Packet */
+#define GMR_FS_BAD_FC  (1L<<6)         /* Bit  6:      Bad  Flow-Control Packet */
+#define GMR_FS_MII_ERR (1L<<5)         /* Bit  5:      MII Error */
+#define GMR_FS_LONG_ERR        (1L<<4)         /* Bit  4:      Too Long Packet */
+#define GMR_FS_FRAGMENT        (1L<<3)         /* Bit  3:      Fragment */
+                                                               /* Bit  2:      reserved */
+#define GMR_FS_CRC_ERR (1L<<1)         /* Bit  1:      CRC Error */
+#define GMR_FS_RX_FF_OV        (1L<<0)         /* Bit  0:      Rx FIFO Overflow */
+
+/*
+ * GMR_FS_ANY_ERR (analogous to XMR_FS_ANY_ERR)
+ */
+#define GMR_FS_ANY_ERR (GMR_FS_CRC_ERR | \
+                       GMR_FS_LONG_ERR | \
+                       GMR_FS_MII_ERR | \
+                       GMR_FS_BAD_FC | \
+                       GMR_FS_GOOD_FC | \
+                       GMR_FS_JABBER)
+
+/* Rx GMAC FIFO Flush Mask (default) */
+#define RX_FF_FL_DEF_MSK       (GMR_FS_CRC_ERR | \
+                       GMR_FS_RX_FF_OV | \
+                       GMR_FS_MII_ERR | \
+                       GMR_FS_BAD_FC | \
+                       GMR_FS_GOOD_FC | \
+                       GMR_FS_UN_SIZE | \
+                       GMR_FS_JABBER)
+
+/* typedefs *******************************************************************/
+
+
+/* function prototypes ********************************************************/
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __INC_XMAC_H */
diff --git a/drivers/net/sk98lin/skaddr.c b/drivers/net/sk98lin/skaddr.c
new file mode 100644 (file)
index 0000000..6e6c56a
--- /dev/null
@@ -0,0 +1,1788 @@
+/******************************************************************************
+ *
+ * Name:       skaddr.c
+ * Project:    Gigabit Ethernet Adapters, ADDR-Module
+ * Version:    $Revision: 1.52 $
+ * Date:       $Date: 2003/06/02 13:46:15 $
+ * Purpose:    Manage Addresses (Multicast and Unicast) and Promiscuous Mode.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *     (C)Copyright 1998-2002 SysKonnect GmbH.
+ *     (C)Copyright 2002-2003 Marvell.
+ *
+ *     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.
+ *
+ *     The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * Description:
+ *
+ * This module is intended to manage multicast addresses, address override,
+ * and promiscuous mode on GEnesis and Yukon adapters.
+ *
+ * Address Layout:
+ *     port address:           physical MAC address
+ *     1st exact match:        logical MAC address (GEnesis only)
+ *     2nd exact match:        RLMT multicast (GEnesis only)
+ *     exact match 3-13:       OS-specific multicasts (GEnesis only)
+ *
+ * Include File Hierarchy:
+ *
+ *     "skdrv1st.h"
+ *     "skdrv2nd.h"
+ *
+ ******************************************************************************/
+
+#if (defined(DEBUG) || ((!defined(LINT)) && (!defined(SK_SLIM))))
+static const char SysKonnectFileId[] =
+       "@(#) $Id: skaddr.c,v 1.52 2003/06/02 13:46:15 tschilli Exp $ (C) Marvell.";
+#endif /* DEBUG ||!LINT || !SK_SLIM */
+
+#define __SKADDR_C
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* cplusplus */
+
+#include "h/skdrv1st.h"
+#include "h/skdrv2nd.h"
+
+/* defines ********************************************************************/
+
+
+#define XMAC_POLY      0xEDB88320UL    /* CRC32-Poly - XMAC: Little Endian */
+#define GMAC_POLY      0x04C11DB7L     /* CRC16-Poly - GMAC: Little Endian */
+#define HASH_BITS      6                               /* #bits in hash */
+#define        SK_MC_BIT       0x01
+
+/* Error numbers and messages. */
+
+#define SKERR_ADDR_E001                (SK_ERRBASE_ADDR + 0)
+#define SKERR_ADDR_E001MSG     "Bad Flags."
+#define SKERR_ADDR_E002                (SKERR_ADDR_E001 + 1)
+#define SKERR_ADDR_E002MSG     "New Error."
+
+/* typedefs *******************************************************************/
+
+/* None. */
+
+/* global variables ***********************************************************/
+
+/* 64-bit hash values with all bits set. */
+
+static const SK_U16    OnesHash[4] = {0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF};
+
+/* local variables ************************************************************/
+
+#ifdef DEBUG
+static int     Next0[SK_MAX_MACS] = {0};
+#endif /* DEBUG */
+
+static int SkAddrGmacMcAdd(SK_AC *pAC, SK_IOC IoC, SK_U32 PortNumber,
+                          SK_MAC_ADDR *pMc, int Flags);
+static int SkAddrGmacMcClear(SK_AC *pAC, SK_IOC IoC, SK_U32 PortNumber,
+                            int Flags);
+static int SkAddrGmacMcUpdate(SK_AC *pAC, SK_IOC IoC, SK_U32 PortNumber);
+static int SkAddrGmacPromiscuousChange(SK_AC *pAC, SK_IOC IoC,
+                                      SK_U32 PortNumber, int NewPromMode);
+static int SkAddrXmacMcAdd(SK_AC *pAC, SK_IOC IoC, SK_U32 PortNumber,
+                          SK_MAC_ADDR *pMc, int Flags);
+static int SkAddrXmacMcClear(SK_AC *pAC, SK_IOC IoC, SK_U32 PortNumber,
+                            int Flags);
+static int SkAddrXmacMcUpdate(SK_AC *pAC, SK_IOC IoC, SK_U32 PortNumber);
+static int SkAddrXmacPromiscuousChange(SK_AC *pAC, SK_IOC IoC,
+                                      SK_U32 PortNumber, int NewPromMode);
+
+/* functions ******************************************************************/
+
+/******************************************************************************
+ *
+ *     SkAddrInit - initialize data, set state to init
+ *
+ * Description:
+ *
+ *     SK_INIT_DATA
+ *     ============
+ *
+ *     This routine clears the multicast tables and resets promiscuous mode.
+ *     Some entries are reserved for the "logical MAC address", the
+ *     SK-RLMT multicast address, and the BPDU multicast address.
+ *
+ *
+ *     SK_INIT_IO
+ *     ==========
+ *
+ *     All permanent MAC addresses are read from EPROM.
+ *     If the current MAC addresses are not already set in software,
+ *     they are set to the values of the permanent addresses.
+ *     The current addresses are written to the corresponding MAC.
+ *
+ *
+ *     SK_INIT_RUN
+ *     ===========
+ *
+ *     Nothing.
+ *
+ * Context:
+ *     init, pageable
+ *
+ * Returns:
+ *     SK_ADDR_SUCCESS
+ */
+int    SkAddrInit(
+SK_AC  *pAC,   /* the adapter context */
+SK_IOC IoC,    /* I/O context */
+int            Level)  /* initialization level */
+{
+       int                     j;
+       SK_U32          i;
+       SK_U8           *InAddr;
+       SK_U16          *OutAddr;
+       SK_ADDR_PORT    *pAPort;
+
+       switch (Level) {
+       case SK_INIT_DATA:
+               SK_MEMSET((char *) &pAC->Addr, (SK_U8) 0,
+            (SK_U16) sizeof(SK_ADDR));
+
+               for (i = 0; i < SK_MAX_MACS; i++) {
+                       pAPort = &pAC->Addr.Port[i];
+                       pAPort->PromMode = SK_PROM_MODE_NONE;
+                       
+                       pAPort->FirstExactMatchRlmt = SK_ADDR_FIRST_MATCH_RLMT;
+                       pAPort->FirstExactMatchDrv = SK_ADDR_FIRST_MATCH_DRV;
+                       pAPort->NextExactMatchRlmt = SK_ADDR_FIRST_MATCH_RLMT;
+                       pAPort->NextExactMatchDrv = SK_ADDR_FIRST_MATCH_DRV;
+               }
+#ifdef xDEBUG
+               for (i = 0; i < SK_MAX_MACS; i++) {
+                       if (pAC->Addr.Port[i].NextExactMatchRlmt <
+                               SK_ADDR_FIRST_MATCH_RLMT) {
+                               Next0[i] |= 4;
+                       }
+               }
+#endif /* DEBUG */
+               /* pAC->Addr.InitDone = SK_INIT_DATA; */
+               break;
+
+    case SK_INIT_IO:
+#ifndef SK_NO_RLMT
+               for (i = 0; i < SK_MAX_NETS; i++) {
+                       pAC->Addr.Net[i].ActivePort = pAC->Rlmt.Net[i].ActivePort;
+               }
+#endif /* !SK_NO_RLMT */
+#ifdef xDEBUG
+               for (i = 0; i < SK_MAX_MACS; i++) {
+                       if (pAC->Addr.Port[i].NextExactMatchRlmt <
+                               SK_ADDR_FIRST_MATCH_RLMT) {
+                               Next0[i] |= 8;
+                       }
+               }
+#endif /* DEBUG */
+               
+               /* Read permanent logical MAC address from Control Register File. */
+               for (j = 0; j < SK_MAC_ADDR_LEN; j++) {
+                       InAddr = (SK_U8 *) &pAC->Addr.Net[0].PermanentMacAddress.a[j];
+                       SK_IN8(IoC, B2_MAC_1 + j, InAddr);
+               }
+
+               if (!pAC->Addr.Net[0].CurrentMacAddressSet) {
+                       /* Set the current logical MAC address to the permanent one. */
+                       pAC->Addr.Net[0].CurrentMacAddress =
+                               pAC->Addr.Net[0].PermanentMacAddress;
+                       pAC->Addr.Net[0].CurrentMacAddressSet = SK_TRUE;
+               }
+
+               /* Set the current logical MAC address. */
+               pAC->Addr.Port[pAC->Addr.Net[0].ActivePort].Exact[0] =
+                       pAC->Addr.Net[0].CurrentMacAddress;
+#if SK_MAX_NETS > 1
+               /* Set logical MAC address for net 2 to (log | 3). */
+               if (!pAC->Addr.Net[1].CurrentMacAddressSet) {
+                       pAC->Addr.Net[1].PermanentMacAddress =
+                               pAC->Addr.Net[0].PermanentMacAddress;
+                       pAC->Addr.Net[1].PermanentMacAddress.a[5] |= 3;
+                       /* Set the current logical MAC address to the permanent one. */
+                       pAC->Addr.Net[1].CurrentMacAddress =
+                               pAC->Addr.Net[1].PermanentMacAddress;
+                       pAC->Addr.Net[1].CurrentMacAddressSet = SK_TRUE;
+               }
+#endif /* SK_MAX_NETS > 1 */
+
+#ifdef DEBUG
+               for (i = 0; i < (SK_U32) pAC->GIni.GIMacsFound; i++) {
+                       SK_DBG_MSG(pAC, SK_DBGMOD_ADDR, SK_DBGCAT_INIT,
+                               ("Permanent MAC Address (Net%d): %02X %02X %02X %02X %02X %02X\n",
+                                       i,
+                                       pAC->Addr.Net[i].PermanentMacAddress.a[0],
+                                       pAC->Addr.Net[i].PermanentMacAddress.a[1],
+                                       pAC->Addr.Net[i].PermanentMacAddress.a[2],
+                                       pAC->Addr.Net[i].PermanentMacAddress.a[3],
+                                       pAC->Addr.Net[i].PermanentMacAddress.a[4],
+                                       pAC->Addr.Net[i].PermanentMacAddress.a[5]))
+                       
+                       SK_DBG_MSG(pAC, SK_DBGMOD_ADDR, SK_DBGCAT_INIT,
+                               ("Logical MAC Address (Net%d): %02X %02X %02X %02X %02X %02X\n",
+                                       i,
+                                       pAC->Addr.Net[i].CurrentMacAddress.a[0],
+                                       pAC->Addr.Net[i].CurrentMacAddress.a[1],
+                                       pAC->Addr.Net[i].CurrentMacAddress.a[2],
+                                       pAC->Addr.Net[i].CurrentMacAddress.a[3],
+                                       pAC->Addr.Net[i].CurrentMacAddress.a[4],
+                                       pAC->Addr.Net[i].CurrentMacAddress.a[5]))
+               }
+#endif /* DEBUG */
+
+               for (i = 0; i < (SK_U32) pAC->GIni.GIMacsFound; i++) {
+                       pAPort = &pAC->Addr.Port[i];
+
+                       /* Read permanent port addresses from Control Register File. */
+                       for (j = 0; j < SK_MAC_ADDR_LEN; j++) {
+                               InAddr = (SK_U8 *) &pAPort->PermanentMacAddress.a[j];
+                               SK_IN8(IoC, B2_MAC_2 + 8 * i + j, InAddr);
+                       }
+
+                       if (!pAPort->CurrentMacAddressSet) {
+                               /*
+                                * Set the current and previous physical MAC address
+                                * of this port to its permanent MAC address.
+                                */
+                               pAPort->CurrentMacAddress = pAPort->PermanentMacAddress;
+                               pAPort->PreviousMacAddress = pAPort->PermanentMacAddress;
+                               pAPort->CurrentMacAddressSet = SK_TRUE;
+                       }
+
+                       /* Set port's current physical MAC address. */
+                       OutAddr = (SK_U16 *) &pAPort->CurrentMacAddress.a[0];
+#ifdef GENESIS
+                       if (pAC->GIni.GIGenesis) {
+                               XM_OUTADDR(IoC, i, XM_SA, OutAddr);
+                       }
+#endif /* GENESIS */
+#ifdef YUKON
+                       if (!pAC->GIni.GIGenesis) {
+                               GM_OUTADDR(IoC, i, GM_SRC_ADDR_1L, OutAddr);
+                       }
+#endif /* YUKON */
+#ifdef DEBUG
+                       SK_DBG_MSG(pAC, SK_DBGMOD_ADDR, SK_DBGCAT_INIT,
+                               ("SkAddrInit: Permanent Physical MAC Address: %02X %02X %02X %02X %02X %02X\n",
+                                       pAPort->PermanentMacAddress.a[0],
+                                       pAPort->PermanentMacAddress.a[1],
+                                       pAPort->PermanentMacAddress.a[2],
+                                       pAPort->PermanentMacAddress.a[3],
+                                       pAPort->PermanentMacAddress.a[4],
+                                       pAPort->PermanentMacAddress.a[5]))
+                       
+                       SK_DBG_MSG(pAC, SK_DBGMOD_ADDR, SK_DBGCAT_INIT,
+                               ("SkAddrInit: Physical MAC Address: %02X %02X %02X %02X %02X %02X\n",
+                                       pAPort->CurrentMacAddress.a[0],
+                                       pAPort->CurrentMacAddress.a[1],
+                                       pAPort->CurrentMacAddress.a[2],
+                                       pAPort->CurrentMacAddress.a[3],
+                                       pAPort->CurrentMacAddress.a[4],
+                                       pAPort->CurrentMacAddress.a[5]))
+#endif /* DEBUG */
+               }
+               /* pAC->Addr.InitDone = SK_INIT_IO; */
+               break;
+
+       case SK_INIT_RUN:
+#ifdef xDEBUG
+               for (i = 0; i < SK_MAX_MACS; i++) {
+                       if (pAC->Addr.Port[i].NextExactMatchRlmt <
+                               SK_ADDR_FIRST_MATCH_RLMT) {
+                               Next0[i] |= 16;
+                       }
+               }
+#endif /* DEBUG */
+
+               /* pAC->Addr.InitDone = SK_INIT_RUN; */
+               break;
+
+       default:        /* error */
+               break;
+       }
+
+       return (SK_ADDR_SUCCESS);
+       
+}      /* SkAddrInit */
+
+#ifndef SK_SLIM
+
+/******************************************************************************
+ *
+ *     SkAddrMcClear - clear the multicast table
+ *
+ * Description:
+ *     This routine clears the multicast table.
+ *
+ *     If not suppressed by Flag SK_MC_SW_ONLY, the hardware is updated
+ *     immediately.
+ *
+ *     It calls either SkAddrXmacMcClear or SkAddrGmacMcClear, according
+ *     to the adapter in use. The real work is done there.
+ *
+ * Context:
+ *     runtime, pageable
+ *     may be called starting with SK_INIT_DATA with flag SK_MC_SW_ONLY
+ *     may be called after SK_INIT_IO without limitation
+ *
+ * Returns:
+ *     SK_ADDR_SUCCESS
+ *     SK_ADDR_ILLEGAL_PORT
+ */
+int    SkAddrMcClear(
+SK_AC  *pAC,           /* adapter context */
+SK_IOC IoC,            /* I/O context */
+SK_U32 PortNumber,     /* Index of affected port */
+int            Flags)          /* permanent/non-perm, sw-only */
+{
+       int ReturnCode;
+       
+       if (PortNumber >= (SK_U32) pAC->GIni.GIMacsFound) {
+               return (SK_ADDR_ILLEGAL_PORT);
+       }
+       
+       if (pAC->GIni.GIGenesis) {
+               ReturnCode = SkAddrXmacMcClear(pAC, IoC, PortNumber, Flags);
+       }
+       else {
+               ReturnCode = SkAddrGmacMcClear(pAC, IoC, PortNumber, Flags);
+       }
+
+       return (ReturnCode);
+
+}      /* SkAddrMcClear */
+
+#endif /* !SK_SLIM */
+
+#ifndef SK_SLIM
+
+/******************************************************************************
+ *
+ *     SkAddrXmacMcClear - clear the multicast table
+ *
+ * Description:
+ *     This routine clears the multicast table
+ *     (either entry 2 or entries 3-16 and InexactFilter) of the given port.
+ *     If not suppressed by Flag SK_MC_SW_ONLY, the hardware is updated
+ *     immediately.
+ *
+ * Context:
+ *     runtime, pageable
+ *     may be called starting with SK_INIT_DATA with flag SK_MC_SW_ONLY
+ *     may be called after SK_INIT_IO without limitation
+ *
+ * Returns:
+ *     SK_ADDR_SUCCESS
+ *     SK_ADDR_ILLEGAL_PORT
+ */
+static int     SkAddrXmacMcClear(
+SK_AC  *pAC,           /* adapter context */
+SK_IOC IoC,            /* I/O context */
+SK_U32 PortNumber,     /* Index of affected port */
+int            Flags)          /* permanent/non-perm, sw-only */
+{
+       int i;
+
+       if (Flags & SK_ADDR_PERMANENT) {        /* permanent => RLMT */
+
+               /* Clear RLMT multicast addresses. */
+               pAC->Addr.Port[PortNumber].NextExactMatchRlmt = SK_ADDR_FIRST_MATCH_RLMT;
+       }
+       else {  /* not permanent => DRV */
+
+               /* Clear InexactFilter */
+               for (i = 0; i < 8; i++) {
+                       pAC->Addr.Port[PortNumber].InexactFilter.Bytes[i] = 0;
+               }
+
+               /* Clear DRV multicast addresses. */
+
+               pAC->Addr.Port[PortNumber].NextExactMatchDrv = SK_ADDR_FIRST_MATCH_DRV;
+       }
+
+       if (!(Flags & SK_MC_SW_ONLY)) {
+               (void) SkAddrXmacMcUpdate(pAC, IoC, PortNumber);
+       }
+
+       return (SK_ADDR_SUCCESS);
+       
+}      /* SkAddrXmacMcClear */
+
+#endif /* !SK_SLIM */
+
+#ifndef SK_SLIM
+
+/******************************************************************************
+ *
+ *     SkAddrGmacMcClear - clear the multicast table
+ *
+ * Description:
+ *     This routine clears the multicast hashing table (InexactFilter)
+ *     (either the RLMT or the driver bits) of the given port.
+ *
+ *     If not suppressed by Flag SK_MC_SW_ONLY, the hardware is updated
+ *     immediately.
+ *
+ * Context:
+ *     runtime, pageable
+ *     may be called starting with SK_INIT_DATA with flag SK_MC_SW_ONLY
+ *     may be called after SK_INIT_IO without limitation
+ *
+ * Returns:
+ *     SK_ADDR_SUCCESS
+ *     SK_ADDR_ILLEGAL_PORT
+ */
+static int     SkAddrGmacMcClear(
+SK_AC  *pAC,           /* adapter context */
+SK_IOC IoC,            /* I/O context */
+SK_U32 PortNumber,     /* Index of affected port */
+int            Flags)          /* permanent/non-perm, sw-only */
+{
+       int i;
+
+#ifdef DEBUG
+       SK_DBG_MSG(pAC, SK_DBGMOD_ADDR, SK_DBGCAT_CTRL,
+               ("GMAC InexactFilter (not cleared): %02X %02X %02X %02X %02X %02X %02X %02X\n",
+                       pAC->Addr.Port[PortNumber].InexactFilter.Bytes[0],
+                       pAC->Addr.Port[PortNumber].InexactFilter.Bytes[1],
+                       pAC->Addr.Port[PortNumber].InexactFilter.Bytes[2],
+                       pAC->Addr.Port[PortNumber].InexactFilter.Bytes[3],
+                       pAC->Addr.Port[PortNumber].InexactFilter.Bytes[4],
+                       pAC->Addr.Port[PortNumber].InexactFilter.Bytes[5],
+                       pAC->Addr.Port[PortNumber].InexactFilter.Bytes[6],
+                       pAC->Addr.Port[PortNumber].InexactFilter.Bytes[7]))
+#endif /* DEBUG */
+
+       /* Clear InexactFilter */
+       for (i = 0; i < 8; i++) {
+               pAC->Addr.Port[PortNumber].InexactFilter.Bytes[i] = 0;
+       }
+       
+       if (Flags & SK_ADDR_PERMANENT) {        /* permanent => RLMT */
+               
+               /* Copy DRV bits to InexactFilter. */
+               for (i = 0; i < 8; i++) {
+                       pAC->Addr.Port[PortNumber].InexactFilter.Bytes[i] |=
+                               pAC->Addr.Port[PortNumber].InexactDrvFilter.Bytes[i];
+                       
+                       /* Clear InexactRlmtFilter. */
+                       pAC->Addr.Port[PortNumber].InexactRlmtFilter.Bytes[i] = 0;
+
+               }               
+       }
+       else {  /* not permanent => DRV */
+               
+               /* Copy RLMT bits to InexactFilter. */
+               for (i = 0; i < 8; i++) {
+                       pAC->Addr.Port[PortNumber].InexactFilter.Bytes[i] |=
+                               pAC->Addr.Port[PortNumber].InexactRlmtFilter.Bytes[i];
+                       
+                       /* Clear InexactDrvFilter. */
+                       pAC->Addr.Port[PortNumber].InexactDrvFilter.Bytes[i] = 0;
+               }
+       }
+       
+#ifdef DEBUG
+       SK_DBG_MSG(pAC, SK_DBGMOD_ADDR, SK_DBGCAT_CTRL,
+               ("GMAC InexactFilter (cleared): %02X %02X %02X %02X %02X %02X %02X %02X\n",
+                       pAC->Addr.Port[PortNumber].InexactFilter.Bytes[0],
+                       pAC->Addr.Port[PortNumber].InexactFilter.Bytes[1],
+                       pAC->Addr.Port[PortNumber].InexactFilter.Bytes[2],
+                       pAC->Addr.Port[PortNumber].InexactFilter.Bytes[3],
+                       pAC->Addr.Port[PortNumber].InexactFilter.Bytes[4],
+                       pAC->Addr.Port[PortNumber].InexactFilter.Bytes[5],
+                       pAC->Addr.Port[PortNumber].InexactFilter.Bytes[6],
+                       pAC->Addr.Port[PortNumber].InexactFilter.Bytes[7]))
+#endif /* DEBUG */
+       
+       if (!(Flags & SK_MC_SW_ONLY)) {
+               (void) SkAddrGmacMcUpdate(pAC, IoC, PortNumber);
+       }
+       
+       return (SK_ADDR_SUCCESS);
+
+}      /* SkAddrGmacMcClear */
+
+#ifndef SK_ADDR_CHEAT
+
+/******************************************************************************
+ *
+ *     SkXmacMcHash - hash multicast address
+ *
+ * Description:
+ *     This routine computes the hash value for a multicast address.
+ *     A CRC32 algorithm is used.
+ *
+ * Notes:
+ *     The code was adapted from the XaQti data sheet.
+ *
+ * Context:
+ *     runtime, pageable
+ *
+ * Returns:
+ *     Hash value of multicast address.
+ */
+static SK_U32 SkXmacMcHash(
+unsigned char *pMc)    /* Multicast address */
+{
+       SK_U32 Idx;
+       SK_U32 Bit;
+       SK_U32 Data;
+       SK_U32 Crc;
+
+       Crc = 0xFFFFFFFFUL;
+       for (Idx = 0; Idx < SK_MAC_ADDR_LEN; Idx++) {
+               Data = *pMc++;
+               for (Bit = 0; Bit < 8; Bit++, Data >>= 1) {
+                       Crc = (Crc >> 1) ^ (((Crc ^ Data) & 1) ? XMAC_POLY : 0);
+               }
+       }
+
+       return (Crc & ((1 << HASH_BITS) - 1));
+
+}      /* SkXmacMcHash */
+
+
+/******************************************************************************
+ *
+ *     SkGmacMcHash - hash multicast address
+ *
+ * Description:
+ *     This routine computes the hash value for a multicast address.
+ *     A CRC16 algorithm is used.
+ *
+ * Notes:
+ *
+ *
+ * Context:
+ *     runtime, pageable
+ *
+ * Returns:
+ *     Hash value of multicast address.
+ */
+static SK_U32 SkGmacMcHash(
+unsigned char *pMc)    /* Multicast address */
+{
+       SK_U32 Data;
+       SK_U32 TmpData;
+       SK_U32 Crc;
+       int Byte;
+       int Bit;
+
+       Crc = 0xFFFFFFFFUL;
+       for (Byte = 0; Byte < 6; Byte++) {
+               /* Get next byte. */
+               Data = (SK_U32) pMc[Byte];
+               
+               /* Change bit order in byte. */
+               TmpData = Data;
+               for (Bit = 0; Bit < 8; Bit++) {
+                       if (TmpData & 1L) {
+                               Data |=  1L << (7 - Bit);
+                       }
+                       else {
+                               Data &= ~(1L << (7 - Bit));
+                       }
+                       TmpData >>= 1;
+               }
+               
+               Crc ^= (Data << 24);
+               for (Bit = 0; Bit < 8; Bit++) {
+                       if (Crc & 0x80000000) {
+                               Crc = (Crc << 1) ^ GMAC_POLY;
+                       }
+                       else {
+                               Crc <<= 1;
+                       }
+               }
+       }
+       
+       return (Crc & ((1 << HASH_BITS) - 1));
+
+}      /* SkGmacMcHash */
+
+#endif /* !SK_ADDR_CHEAT */
+
+/******************************************************************************
+ *
+ *     SkAddrMcAdd - add a multicast address to a port
+ *
+ * Description:
+ *     This routine enables reception for a given address on the given port.
+ *
+ *     It calls either SkAddrXmacMcAdd or SkAddrGmacMcAdd, according to the
+ *     adapter in use. The real work is done there.
+ *
+ * Notes:
+ *     The return code is only valid for SK_PROM_MODE_NONE.
+ *
+ * Context:
+ *     runtime, pageable
+ *     may be called after SK_INIT_DATA
+ *
+ * Returns:
+ *     SK_MC_FILTERING_EXACT
+ *     SK_MC_FILTERING_INEXACT
+ *     SK_MC_ILLEGAL_ADDRESS
+ *     SK_MC_ILLEGAL_PORT
+ *     SK_MC_RLMT_OVERFLOW
+ */
+int    SkAddrMcAdd(
+SK_AC          *pAC,           /* adapter context */
+SK_IOC         IoC,            /* I/O context */
+SK_U32         PortNumber,     /* Port Number */
+SK_MAC_ADDR    *pMc,           /* multicast address to be added */
+int                    Flags)          /* permanent/non-permanent */
+{
+       int ReturnCode;
+       
+       if (PortNumber >= (SK_U32) pAC->GIni.GIMacsFound) {
+               return (SK_ADDR_ILLEGAL_PORT);
+       }
+       
+       if (pAC->GIni.GIGenesis) {
+               ReturnCode = SkAddrXmacMcAdd(pAC, IoC, PortNumber, pMc, Flags);
+       }
+       else {
+               ReturnCode = SkAddrGmacMcAdd(pAC, IoC, PortNumber, pMc, Flags);
+       }
+
+       return (ReturnCode);
+
+}      /* SkAddrMcAdd */
+
+
+/******************************************************************************
+ *
+ *     SkAddrXmacMcAdd - add a multicast address to a port
+ *
+ * Description:
+ *     This routine enables reception for a given address on the given port.
+ *
+ * Notes:
+ *     The return code is only valid for SK_PROM_MODE_NONE.
+ *
+ *     The multicast bit is only checked if there are no free exact match
+ *     entries.
+ *
+ * Context:
+ *     runtime, pageable
+ *     may be called after SK_INIT_DATA
+ *
+ * Returns:
+ *     SK_MC_FILTERING_EXACT
+ *     SK_MC_FILTERING_INEXACT
+ *     SK_MC_ILLEGAL_ADDRESS
+ *     SK_MC_RLMT_OVERFLOW
+ */
+static int     SkAddrXmacMcAdd(
+SK_AC          *pAC,           /* adapter context */
+SK_IOC         IoC,            /* I/O context */
+SK_U32         PortNumber,     /* Port Number */
+SK_MAC_ADDR    *pMc,           /* multicast address to be added */
+int            Flags)          /* permanent/non-permanent */
+{
+       int     i;
+       SK_U8   Inexact;
+#ifndef SK_ADDR_CHEAT
+       SK_U32 HashBit;
+#endif /* !defined(SK_ADDR_CHEAT) */
+
+       if (Flags & SK_ADDR_PERMANENT) {        /* permanent => RLMT */
+#ifdef xDEBUG
+               if (pAC->Addr.Port[PortNumber].NextExactMatchRlmt <
+                       SK_ADDR_FIRST_MATCH_RLMT) {
+                       Next0[PortNumber] |= 1;
+                       return (SK_MC_RLMT_OVERFLOW);
+               }
+#endif /* DEBUG */
+               
+               if (pAC->Addr.Port[PortNumber].NextExactMatchRlmt >
+                       SK_ADDR_LAST_MATCH_RLMT) {
+                       return (SK_MC_RLMT_OVERFLOW);
+               }
+
+               /* Set a RLMT multicast address. */
+
+               pAC->Addr.Port[PortNumber].Exact[
+                       pAC->Addr.Port[PortNumber].NextExactMatchRlmt++] = *pMc;
+
+               return (SK_MC_FILTERING_EXACT);
+       }
+
+#ifdef xDEBUG
+       if (pAC->Addr.Port[PortNumber].NextExactMatchDrv <
+               SK_ADDR_FIRST_MATCH_DRV) {
+                       Next0[PortNumber] |= 2;
+               return (SK_MC_RLMT_OVERFLOW);
+       }
+#endif /* DEBUG */
+       
+       if (pAC->Addr.Port[PortNumber].NextExactMatchDrv <= SK_ADDR_LAST_MATCH_DRV) {
+
+               /* Set exact match entry. */
+               pAC->Addr.Port[PortNumber].Exact[
+                       pAC->Addr.Port[PortNumber].NextExactMatchDrv++] = *pMc;
+
+               /* Clear InexactFilter */
+               for (i = 0; i < 8; i++) {
+                       pAC->Addr.Port[PortNumber].InexactFilter.Bytes[i] = 0;
+               }
+       }
+       else {
+               if (!(pMc->a[0] & SK_MC_BIT)) {
+                       /* Hashing only possible with multicast addresses */
+                       return (SK_MC_ILLEGAL_ADDRESS);
+               }
+#ifndef SK_ADDR_CHEAT
+               /* Compute hash value of address. */
+               HashBit = 63 - SkXmacMcHash(&pMc->a[0]);
+
+               /* Add bit to InexactFilter. */
+               pAC->Addr.Port[PortNumber].InexactFilter.Bytes[HashBit / 8] |=
+                       1 << (HashBit % 8);
+#else  /* SK_ADDR_CHEAT */
+               /* Set all bits in InexactFilter. */
+               for (i = 0; i < 8; i++) {
+                       pAC->Addr.Port[PortNumber].InexactFilter.Bytes[i] = 0xFF;
+               }
+#endif /* SK_ADDR_CHEAT */
+       }
+
+       for (Inexact = 0, i = 0; i < 8; i++) {
+               Inexact |= pAC->Addr.Port[PortNumber].InexactFilter.Bytes[i];
+       }
+
+       if (Inexact == 0 && pAC->Addr.Port[PortNumber].PromMode == 0) {
+               return (SK_MC_FILTERING_EXACT);
+       }
+       else {
+               return (SK_MC_FILTERING_INEXACT);
+       }
+
+}      /* SkAddrXmacMcAdd */
+
+
+/******************************************************************************
+ *
+ *     SkAddrGmacMcAdd - add a multicast address to a port
+ *
+ * Description:
+ *     This routine enables reception for a given address on the given port.
+ *
+ * Notes:
+ *     The return code is only valid for SK_PROM_MODE_NONE.
+ *
+ * Context:
+ *     runtime, pageable
+ *     may be called after SK_INIT_DATA
+ *
+ * Returns:
+ *     SK_MC_FILTERING_INEXACT
+ *     SK_MC_ILLEGAL_ADDRESS
+ */
+static int     SkAddrGmacMcAdd(
+SK_AC          *pAC,           /* adapter context */
+SK_IOC         IoC,            /* I/O context */
+SK_U32         PortNumber,     /* Port Number */
+SK_MAC_ADDR    *pMc,           /* multicast address to be added */
+int            Flags)          /* permanent/non-permanent */
+{
+       int     i;
+#ifndef SK_ADDR_CHEAT
+       SK_U32 HashBit;
+#endif /* !defined(SK_ADDR_CHEAT) */
+               
+       if (!(pMc->a[0] & SK_MC_BIT)) {
+               /* Hashing only possible with multicast addresses */
+               return (SK_MC_ILLEGAL_ADDRESS);
+       }
+       
+#ifndef SK_ADDR_CHEAT
+       
+       /* Compute hash value of address. */
+       HashBit = SkGmacMcHash(&pMc->a[0]);
+       
+       if (Flags & SK_ADDR_PERMANENT) {        /* permanent => RLMT */
+               
+               /* Add bit to InexactRlmtFilter. */
+               pAC->Addr.Port[PortNumber].InexactRlmtFilter.Bytes[HashBit / 8] |=
+                       1 << (HashBit % 8);
+               
+               /* Copy bit to InexactFilter. */
+               for (i = 0; i < 8; i++) {
+                       pAC->Addr.Port[PortNumber].InexactFilter.Bytes[i] |=
+                               pAC->Addr.Port[PortNumber].InexactRlmtFilter.Bytes[i];
+               }
+#ifdef DEBUG
+               SK_DBG_MSG(pAC, SK_DBGMOD_ADDR, SK_DBGCAT_CTRL,
+               ("GMAC InexactRlmtFilter: %02X %02X %02X %02X %02X %02X %02X %02X\n",
+                       pAC->Addr.Port[PortNumber].InexactRlmtFilter.Bytes[0],
+                       pAC->Addr.Port[PortNumber].InexactRlmtFilter.Bytes[1],
+                       pAC->Addr.Port[PortNumber].InexactRlmtFilter.Bytes[2],
+                       pAC->Addr.Port[PortNumber].InexactRlmtFilter.Bytes[3],
+                       pAC->Addr.Port[PortNumber].InexactRlmtFilter.Bytes[4],
+                       pAC->Addr.Port[PortNumber].InexactRlmtFilter.Bytes[5],
+                       pAC->Addr.Port[PortNumber].InexactRlmtFilter.Bytes[6],
+                       pAC->Addr.Port[PortNumber].InexactRlmtFilter.Bytes[7]))
+#endif /* DEBUG */
+       }
+       else {  /* not permanent => DRV */
+               
+               /* Add bit to InexactDrvFilter. */
+               pAC->Addr.Port[PortNumber].InexactDrvFilter.Bytes[HashBit / 8] |=
+                       1 << (HashBit % 8);
+               
+               /* Copy bit to InexactFilter. */
+               for (i = 0; i < 8; i++) {
+                       pAC->Addr.Port[PortNumber].InexactFilter.Bytes[i] |=
+                               pAC->Addr.Port[PortNumber].InexactDrvFilter.Bytes[i];
+               }
+#ifdef DEBUG
+               SK_DBG_MSG(pAC, SK_DBGMOD_ADDR, SK_DBGCAT_CTRL,
+               ("GMAC InexactDrvFilter: %02X %02X %02X %02X %02X %02X %02X %02X\n",
+                       pAC->Addr.Port[PortNumber].InexactDrvFilter.Bytes[0],
+                       pAC->Addr.Port[PortNumber].InexactDrvFilter.Bytes[1],
+                       pAC->Addr.Port[PortNumber].InexactDrvFilter.Bytes[2],
+                       pAC->Addr.Port[PortNumber].InexactDrvFilter.Bytes[3],
+                       pAC->Addr.Port[PortNumber].InexactDrvFilter.Bytes[4],
+                       pAC->Addr.Port[PortNumber].InexactDrvFilter.Bytes[5],
+                       pAC->Addr.Port[PortNumber].InexactDrvFilter.Bytes[6],
+                       pAC->Addr.Port[PortNumber].InexactDrvFilter.Bytes[7]))
+#endif /* DEBUG */
+       }
+       
+#else  /* SK_ADDR_CHEAT */
+       
+       /* Set all bits in InexactFilter. */
+       for (i = 0; i < 8; i++) {
+               pAC->Addr.Port[PortNumber].InexactFilter.Bytes[i] = 0xFF;
+       }
+#endif /* SK_ADDR_CHEAT */
+               
+       return (SK_MC_FILTERING_INEXACT);
+       
+}      /* SkAddrGmacMcAdd */
+
+#endif /* !SK_SLIM */
+
+/******************************************************************************
+ *
+ *     SkAddrMcUpdate - update the HW MC address table and set the MAC address
+ *
+ * Description:
+ *     This routine enables reception of the addresses contained in a local
+ *     table for a given port.
+ *     It also programs the port's current physical MAC address.
+ *
+ *     It calls either SkAddrXmacMcUpdate or SkAddrGmacMcUpdate, according
+ *     to the adapter in use. The real work is done there.
+ *
+ * Notes:
+ *     The return code is only valid for SK_PROM_MODE_NONE.
+ *
+ * Context:
+ *     runtime, pageable
+ *     may be called after SK_INIT_IO
+ *
+ * Returns:
+ *     SK_MC_FILTERING_EXACT
+ *     SK_MC_FILTERING_INEXACT
+ *     SK_ADDR_ILLEGAL_PORT
+ */
+int    SkAddrMcUpdate(
+SK_AC  *pAC,           /* adapter context */
+SK_IOC IoC,            /* I/O context */
+SK_U32 PortNumber)     /* Port Number */
+{
+       int ReturnCode = 0;
+#if (!defined(SK_SLIM) || defined(DEBUG))
+       if (PortNumber >= (SK_U32) pAC->GIni.GIMacsFound) {
+               return (SK_ADDR_ILLEGAL_PORT);
+       }
+#endif /* !SK_SLIM || DEBUG */
+
+#ifdef GENESIS
+       if (pAC->GIni.GIGenesis) {
+               ReturnCode = SkAddrXmacMcUpdate(pAC, IoC, PortNumber);
+       }
+#endif /* GENESIS */
+#ifdef YUKON
+       if (!pAC->GIni.GIGenesis) {
+               ReturnCode = SkAddrGmacMcUpdate(pAC, IoC, PortNumber);
+       }
+#endif /* YUKON */
+       return (ReturnCode);
+
+}      /* SkAddrMcUpdate */
+
+
+#ifdef GENESIS
+
+/******************************************************************************
+ *
+ *     SkAddrXmacMcUpdate - update the HW MC address table and set the MAC address
+ *
+ * Description:
+ *     This routine enables reception of the addresses contained in a local
+ *     table for a given port.
+ *     It also programs the port's current physical MAC address.
+ *
+ * Notes:
+ *     The return code is only valid for SK_PROM_MODE_NONE.
+ *
+ * Context:
+ *     runtime, pageable
+ *     may be called after SK_INIT_IO
+ *
+ * Returns:
+ *     SK_MC_FILTERING_EXACT
+ *     SK_MC_FILTERING_INEXACT
+ *     SK_ADDR_ILLEGAL_PORT
+ */
+static int     SkAddrXmacMcUpdate(
+SK_AC  *pAC,           /* adapter context */
+SK_IOC IoC,            /* I/O context */
+SK_U32 PortNumber)     /* Port Number */
+{
+       SK_U32          i;
+       SK_U8           Inexact;
+       SK_U16          *OutAddr;
+       SK_ADDR_PORT    *pAPort;
+
+       SK_DBG_MSG(pAC,SK_DBGMOD_ADDR, SK_DBGCAT_CTRL,
+               ("SkAddrXmacMcUpdate on Port %u.\n", PortNumber))
+       
+       pAPort = &pAC->Addr.Port[PortNumber];
+
+#ifdef DEBUG
+       SK_DBG_MSG(pAC,SK_DBGMOD_ADDR, SK_DBGCAT_CTRL,
+               ("Next0 on Port %d: %d\n", PortNumber, Next0[PortNumber]))
+#endif /* DEBUG */
+
+       /* Start with 0 to also program the logical MAC address. */
+       for (i = 0; i < pAPort->NextExactMatchRlmt; i++) {
+               /* Set exact match address i on XMAC */
+               OutAddr = (SK_U16 *) &pAPort->Exact[i].a[0];
+               XM_OUTADDR(IoC, PortNumber, XM_EXM(i), OutAddr);
+       }
+
+       /* Clear other permanent exact match addresses on XMAC */
+       if (pAPort->NextExactMatchRlmt <= SK_ADDR_LAST_MATCH_RLMT) {
+               
+               SkXmClrExactAddr(pAC, IoC, PortNumber, pAPort->NextExactMatchRlmt,
+                       SK_ADDR_LAST_MATCH_RLMT);
+       }
+
+       for (i = pAPort->FirstExactMatchDrv; i < pAPort->NextExactMatchDrv; i++) {
+               OutAddr = (SK_U16 *) &pAPort->Exact[i].a[0];
+               XM_OUTADDR(IoC, PortNumber, XM_EXM(i), OutAddr);
+       }
+
+       /* Clear other non-permanent exact match addresses on XMAC */
+       if (pAPort->NextExactMatchDrv <= SK_ADDR_LAST_MATCH_DRV) {
+               
+               SkXmClrExactAddr(pAC, IoC, PortNumber, pAPort->NextExactMatchDrv,
+                       SK_ADDR_LAST_MATCH_DRV);
+       }
+
+       for (Inexact = 0, i = 0; i < 8; i++) {
+               Inexact |= pAPort->InexactFilter.Bytes[i];
+       }
+
+       if (pAPort->PromMode & SK_PROM_MODE_ALL_MC) {
+               
+               /* Set all bits in 64-bit hash register. */
+               XM_OUTHASH(IoC, PortNumber, XM_HSM, &OnesHash);
+               
+               /* Enable Hashing */
+               SkMacHashing(pAC, IoC, (int) PortNumber, SK_TRUE);
+       }
+       else if (Inexact != 0) {
+               
+               /* Set 64-bit hash register to InexactFilter. */
+               XM_OUTHASH(IoC, PortNumber, XM_HSM, &pAPort->InexactFilter.Bytes[0]);
+               
+               /* Enable Hashing */
+               SkMacHashing(pAC, IoC, (int) PortNumber, SK_TRUE);
+       }
+       else {
+               /* Disable Hashing */
+               SkMacHashing(pAC, IoC, (int) PortNumber, SK_FALSE);
+       }
+
+       if (pAPort->PromMode != SK_PROM_MODE_NONE) {
+               (void) SkAddrXmacPromiscuousChange(pAC, IoC, PortNumber, pAPort->PromMode);
+       }
+
+       /* Set port's current physical MAC address. */
+       OutAddr = (SK_U16 *) &pAPort->CurrentMacAddress.a[0];
+       
+       XM_OUTADDR(IoC, PortNumber, XM_SA, OutAddr);
+
+#ifdef xDEBUG
+       for (i = 0; i < pAPort->NextExactMatchRlmt; i++) {
+               SK_U8           InAddr8[6];
+               SK_U16          *InAddr;
+
+               /* Get exact match address i from port PortNumber. */
+               InAddr = (SK_U16 *) &InAddr8[0];
+               
+               XM_INADDR(IoC, PortNumber, XM_EXM(i), InAddr);
+               
+               SK_DBG_MSG(pAC,SK_DBGMOD_ADDR, SK_DBGCAT_CTRL,
+                       ("SkAddrXmacMcUpdate: MC address %d on Port %u: ",
+                        "%02x %02x %02x %02x %02x %02x -- %02x %02x %02x %02x %02x %02x\n",
+                               i,
+                               PortNumber,
+                               InAddr8[0],
+                               InAddr8[1],
+                               InAddr8[2],
+                               InAddr8[3],
+                               InAddr8[4],
+                               InAddr8[5],
+                               pAPort->Exact[i].a[0],
+                               pAPort->Exact[i].a[1],
+                               pAPort->Exact[i].a[2],
+                               pAPort->Exact[i].a[3],
+                               pAPort->Exact[i].a[4],
+                               pAPort->Exact[i].a[5]))
+       }
+#endif /* DEBUG */
+
+       /* Determine return value. */
+       if (Inexact == 0 && pAPort->PromMode == 0) {
+               return (SK_MC_FILTERING_EXACT);
+       }
+       else {
+               return (SK_MC_FILTERING_INEXACT);
+       }
+       
+}      /* SkAddrXmacMcUpdate */
+
+#endif  /* GENESIS */
+
+#ifdef YUKON
+
+/******************************************************************************
+ *
+ *     SkAddrGmacMcUpdate - update the HW MC address table and set the MAC address
+ *
+ * Description:
+ *     This routine enables reception of the addresses contained in a local
+ *     table for a given port.
+ *     It also programs the port's current physical MAC address.
+ *
+ * Notes:
+ *     The return code is only valid for SK_PROM_MODE_NONE.
+ *
+ * Context:
+ *     runtime, pageable
+ *     may be called after SK_INIT_IO
+ *
+ * Returns:
+ *     SK_MC_FILTERING_EXACT
+ *     SK_MC_FILTERING_INEXACT
+ *     SK_ADDR_ILLEGAL_PORT
+ */
+static int     SkAddrGmacMcUpdate(
+SK_AC  *pAC,           /* adapter context */
+SK_IOC IoC,            /* I/O context */
+SK_U32 PortNumber)     /* Port Number */
+{
+#ifndef SK_SLIM
+       SK_U32          i;
+       SK_U8           Inexact;
+#endif /* not SK_SLIM */
+       SK_U16          *OutAddr;
+       SK_ADDR_PORT    *pAPort;
+
+       SK_DBG_MSG(pAC,SK_DBGMOD_ADDR, SK_DBGCAT_CTRL,
+               ("SkAddrGmacMcUpdate on Port %u.\n", PortNumber))
+       
+       pAPort = &pAC->Addr.Port[PortNumber];
+
+#ifdef DEBUG
+       SK_DBG_MSG(pAC,SK_DBGMOD_ADDR, SK_DBGCAT_CTRL,
+               ("Next0 on Port %d: %d\n", PortNumber, Next0[PortNumber]))
+#endif /* DEBUG */
+       
+#ifndef SK_SLIM
+       for (Inexact = 0, i = 0; i < 8; i++) {
+               Inexact |= pAPort->InexactFilter.Bytes[i];
+       }
+       
+       /* Set 64-bit hash register to InexactFilter. */
+       GM_OUTHASH(IoC, PortNumber, GM_MC_ADDR_H1,
+               &pAPort->InexactFilter.Bytes[0]);
+       
+       if (pAPort->PromMode & SK_PROM_MODE_ALL_MC) {                           
+               
+               /* Set all bits in 64-bit hash register. */
+               GM_OUTHASH(IoC, PortNumber, GM_MC_ADDR_H1, &OnesHash);
+               
+               /* Enable Hashing */
+               SkMacHashing(pAC, IoC, (int) PortNumber, SK_TRUE);
+       }
+       else {  
+               /* Enable Hashing. */
+               SkMacHashing(pAC, IoC, (int) PortNumber, SK_TRUE);
+       }
+       
+       if (pAPort->PromMode != SK_PROM_MODE_NONE) {
+               (void) SkAddrGmacPromiscuousChange(pAC, IoC, PortNumber, pAPort->PromMode);
+       }
+#else /* SK_SLIM */
+
+       /* Set all bits in 64-bit hash register. */
+       GM_OUTHASH(IoC, PortNumber, GM_MC_ADDR_H1, &OnesHash);
+
+       /* Enable Hashing */
+       SkMacHashing(pAC, IoC, (int) PortNumber, SK_TRUE);
+       
+       (void) SkAddrGmacPromiscuousChange(pAC, IoC, PortNumber, pAPort->PromMode);
+       
+#endif /* SK_SLIM */
+       
+       /* Set port's current physical MAC address. */
+       OutAddr = (SK_U16 *) &pAPort->CurrentMacAddress.a[0];
+       GM_OUTADDR(IoC, PortNumber, GM_SRC_ADDR_1L, OutAddr);
+       
+       /* Set port's current logical MAC address. */
+       OutAddr = (SK_U16 *) &pAPort->Exact[0].a[0];
+       GM_OUTADDR(IoC, PortNumber, GM_SRC_ADDR_2L, OutAddr);
+       
+#ifdef DEBUG
+       SK_DBG_MSG(pAC, SK_DBGMOD_ADDR, SK_DBGCAT_CTRL,
+               ("SkAddrGmacMcUpdate: Permanent Physical MAC Address: %02X %02X %02X %02X %02X %02X\n",
+                       pAPort->Exact[0].a[0],
+                       pAPort->Exact[0].a[1],
+                       pAPort->Exact[0].a[2],
+                       pAPort->Exact[0].a[3],
+                       pAPort->Exact[0].a[4],
+                       pAPort->Exact[0].a[5]))
+       
+       SK_DBG_MSG(pAC, SK_DBGMOD_ADDR, SK_DBGCAT_CTRL,
+               ("SkAddrGmacMcUpdate: Physical MAC Address: %02X %02X %02X %02X %02X %02X\n",
+                       pAPort->CurrentMacAddress.a[0],
+                       pAPort->CurrentMacAddress.a[1],
+                       pAPort->CurrentMacAddress.a[2],
+                       pAPort->CurrentMacAddress.a[3],
+                       pAPort->CurrentMacAddress.a[4],
+                       pAPort->CurrentMacAddress.a[5]))
+#endif /* DEBUG */
+       
+#ifndef SK_SLIM
+       /* Determine return value. */
+       if (Inexact == 0 && pAPort->PromMode == 0) {
+               return (SK_MC_FILTERING_EXACT);
+       }
+       else {
+               return (SK_MC_FILTERING_INEXACT);
+       }
+#else /* SK_SLIM */
+       return (SK_MC_FILTERING_INEXACT);
+#endif /* SK_SLIM */
+       
+}      /* SkAddrGmacMcUpdate */
+
+#endif /* YUKON */
+
+#ifndef SK_NO_MAO
+
+/******************************************************************************
+ *
+ *     SkAddrOverride - override a port's MAC address
+ *
+ * Description:
+ *     This routine overrides the MAC address of one port.
+ *
+ * Context:
+ *     runtime, pageable
+ *     may be called after SK_INIT_IO
+ *
+ * Returns:
+ *     SK_ADDR_SUCCESS if successful.
+ *     SK_ADDR_DUPLICATE_ADDRESS if duplicate MAC address.
+ *     SK_ADDR_MULTICAST_ADDRESS if multicast or broadcast address.
+ *     SK_ADDR_TOO_EARLY if SK_INIT_IO was not executed before.
+ */
+int    SkAddrOverride(
+SK_AC          *pAC,                           /* adapter context */
+SK_IOC         IoC,                            /* I/O context */
+SK_U32         PortNumber,                     /* Port Number */
+SK_MAC_ADDR    SK_FAR *pNewAddr,       /* new MAC address */
+int                    Flags)                          /* logical/physical MAC address */
+{
+#ifndef SK_NO_RLMT
+       SK_EVPARA       Para;
+#endif /* !SK_NO_RLMT */
+       SK_U32          NetNumber;
+       SK_U32          i;
+       SK_U16          SK_FAR *OutAddr;
+
+#ifndef SK_NO_RLMT
+       NetNumber = pAC->Rlmt.Port[PortNumber].Net->NetNumber;
+#else
+       NetNumber = 0;
+#endif /* SK_NO_RLMT */
+#if (!defined(SK_SLIM) || defined(DEBUG))
+       if (PortNumber >= (SK_U32) pAC->GIni.GIMacsFound) {
+               return (SK_ADDR_ILLEGAL_PORT);
+       }
+#endif /* !SK_SLIM || DEBUG */
+       if (pNewAddr != NULL && (pNewAddr->a[0] & SK_MC_BIT) != 0) {
+               return (SK_ADDR_MULTICAST_ADDRESS);
+       }
+
+       if (!pAC->Addr.Net[NetNumber].CurrentMacAddressSet) {
+               return (SK_ADDR_TOO_EARLY);
+       }
+
+       if (Flags & SK_ADDR_SET_LOGICAL) {      /* Activate logical MAC address. */
+               /* Parameter *pNewAddr is ignored. */
+               for (i = 0; i < (SK_U32) pAC->GIni.GIMacsFound; i++) {
+                       if (!pAC->Addr.Port[i].CurrentMacAddressSet) {
+                               return (SK_ADDR_TOO_EARLY);
+                       }
+               }
+#ifndef SK_NO_RLMT
+               /* Set PortNumber to number of net's active port. */
+               PortNumber = pAC->Rlmt.Net[NetNumber].
+                       Port[pAC->Addr.Net[NetNumber].ActivePort]->PortNumber;
+#endif /* !SK_NO_RLMT */
+               pAC->Addr.Port[PortNumber].Exact[0] =
+                       pAC->Addr.Net[NetNumber].CurrentMacAddress;
+
+               /* Write address to first exact match entry of active port. */
+               (void) SkAddrMcUpdate(pAC, IoC, PortNumber);
+       }
+       else if (Flags & SK_ADDR_CLEAR_LOGICAL) {
+               /* Deactivate logical MAC address. */
+               /* Parameter *pNewAddr is ignored. */
+               for (i = 0; i < (SK_U32) pAC->GIni.GIMacsFound; i++) {
+                       if (!pAC->Addr.Port[i].CurrentMacAddressSet) {
+                               return (SK_ADDR_TOO_EARLY);
+                       }
+               }
+#ifndef SK_NO_RLMT
+               /* Set PortNumber to number of net's active port. */
+               PortNumber = pAC->Rlmt.Net[NetNumber].
+                       Port[pAC->Addr.Net[NetNumber].ActivePort]->PortNumber;
+#endif /* !SK_NO_RLMT */
+               for (i = 0; i < SK_MAC_ADDR_LEN; i++ ) {
+                       pAC->Addr.Port[PortNumber].Exact[0].a[i] = 0;
+               }
+
+               /* Write address to first exact match entry of active port. */
+               (void) SkAddrMcUpdate(pAC, IoC, PortNumber);
+       }
+       else if (Flags & SK_ADDR_PHYSICAL_ADDRESS) {    /* Physical MAC address. */
+               if (SK_ADDR_EQUAL(pNewAddr->a,
+                       pAC->Addr.Net[NetNumber].CurrentMacAddress.a)) {
+                       return (SK_ADDR_DUPLICATE_ADDRESS);
+               }
+
+               for (i = 0; i < (SK_U32) pAC->GIni.GIMacsFound; i++) {
+                       if (!pAC->Addr.Port[i].CurrentMacAddressSet) {
+                               return (SK_ADDR_TOO_EARLY);
+                       }
+
+                       if (SK_ADDR_EQUAL(pNewAddr->a,
+                               pAC->Addr.Port[i].CurrentMacAddress.a)) {
+                               if (i == PortNumber) {
+                                       return (SK_ADDR_SUCCESS);
+                               }
+                               else {
+                                       return (SK_ADDR_DUPLICATE_ADDRESS);
+                               }
+                       }
+               }
+
+               pAC->Addr.Port[PortNumber].PreviousMacAddress =
+                       pAC->Addr.Port[PortNumber].CurrentMacAddress;
+               pAC->Addr.Port[PortNumber].CurrentMacAddress = *pNewAddr;
+
+               /* Change port's physical MAC address. */
+               OutAddr = (SK_U16 SK_FAR *) pNewAddr;
+#ifdef GENESIS
+               if (pAC->GIni.GIGenesis) {
+                       XM_OUTADDR(IoC, PortNumber, XM_SA, OutAddr);
+               }
+#endif /* GENESIS */
+#ifdef YUKON
+               if (!pAC->GIni.GIGenesis) {
+                       GM_OUTADDR(IoC, PortNumber, GM_SRC_ADDR_1L, OutAddr);
+               }
+#endif /* YUKON */
+
+#ifndef SK_NO_RLMT
+               /* Report address change to RLMT. */
+               Para.Para32[0] = PortNumber;
+               Para.Para32[0] = -1;
+               SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_PORT_ADDR, Para);
+#endif /* !SK_NO_RLMT */
+       }
+       else {  /* Logical MAC address. */
+               if (SK_ADDR_EQUAL(pNewAddr->a,
+                       pAC->Addr.Net[NetNumber].CurrentMacAddress.a)) {
+                       return (SK_ADDR_SUCCESS);
+               }
+               
+               for (i = 0; i < (SK_U32) pAC->GIni.GIMacsFound; i++) {
+                       if (!pAC->Addr.Port[i].CurrentMacAddressSet) {
+                               return (SK_ADDR_TOO_EARLY);
+                       }
+
+                       if (SK_ADDR_EQUAL(pNewAddr->a,
+                               pAC->Addr.Port[i].CurrentMacAddress.a)) {
+                               return (SK_ADDR_DUPLICATE_ADDRESS);
+                       }
+               }
+               
+               /*
+                * In case that the physical and the logical MAC addresses are equal
+                * we must also change the physical MAC address here.
+                * In this case we have an adapter which initially was programmed with
+                * two identical MAC addresses.
+                */
+               if (SK_ADDR_EQUAL(pAC->Addr.Port[PortNumber].CurrentMacAddress.a,
+                               pAC->Addr.Port[PortNumber].Exact[0].a)) {
+                       
+                       pAC->Addr.Port[PortNumber].PreviousMacAddress =
+                               pAC->Addr.Port[PortNumber].CurrentMacAddress;
+                       pAC->Addr.Port[PortNumber].CurrentMacAddress = *pNewAddr;
+                       
+#ifndef SK_NO_RLMT
+                       /* Report address change to RLMT. */
+                       Para.Para32[0] = PortNumber;
+                       Para.Para32[0] = -1;
+                       SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_PORT_ADDR, Para);
+#endif /* !SK_NO_RLMT */
+               }
+               
+#ifndef SK_NO_RLMT
+               /* Set PortNumber to number of net's active port. */
+               PortNumber = pAC->Rlmt.Net[NetNumber].
+                       Port[pAC->Addr.Net[NetNumber].ActivePort]->PortNumber;
+#endif /* !SK_NO_RLMT */
+               pAC->Addr.Net[NetNumber].CurrentMacAddress = *pNewAddr;
+               pAC->Addr.Port[PortNumber].Exact[0] = *pNewAddr;
+#ifdef DEBUG
+               SK_DBG_MSG(pAC,SK_DBGMOD_ADDR, SK_DBGCAT_CTRL,
+                       ("SkAddrOverride: Permanent MAC Address: %02X %02X %02X %02X %02X %02X\n",
+                               pAC->Addr.Net[NetNumber].PermanentMacAddress.a[0],
+                               pAC->Addr.Net[NetNumber].PermanentMacAddress.a[1],
+                               pAC->Addr.Net[NetNumber].PermanentMacAddress.a[2],
+                               pAC->Addr.Net[NetNumber].PermanentMacAddress.a[3],
+                               pAC->Addr.Net[NetNumber].PermanentMacAddress.a[4],
+                               pAC->Addr.Net[NetNumber].PermanentMacAddress.a[5]))
+               
+               SK_DBG_MSG(pAC,SK_DBGMOD_ADDR, SK_DBGCAT_CTRL,
+                       ("SkAddrOverride: New logical MAC Address: %02X %02X %02X %02X %02X %02X\n",
+                               pAC->Addr.Net[NetNumber].CurrentMacAddress.a[0],
+                               pAC->Addr.Net[NetNumber].CurrentMacAddress.a[1],
+                               pAC->Addr.Net[NetNumber].CurrentMacAddress.a[2],
+                               pAC->Addr.Net[NetNumber].CurrentMacAddress.a[3],
+                               pAC->Addr.Net[NetNumber].CurrentMacAddress.a[4],
+                               pAC->Addr.Net[NetNumber].CurrentMacAddress.a[5]))
+#endif /* DEBUG */
+
+        /* Write address to first exact match entry of active port. */
+               (void) SkAddrMcUpdate(pAC, IoC, PortNumber);
+       }
+
+       return (SK_ADDR_SUCCESS);
+       
+}      /* SkAddrOverride */
+
+
+#endif /* SK_NO_MAO */
+
+/******************************************************************************
+ *
+ *     SkAddrPromiscuousChange - set promiscuous mode for given port
+ *
+ * Description:
+ *     This routine manages promiscuous mode:
+ *     - none
+ *     - all LLC frames
+ *     - all MC frames
+ *
+ *     It calls either SkAddrXmacPromiscuousChange or
+ *     SkAddrGmacPromiscuousChange, according to the adapter in use.
+ *     The real work is done there.
+ *
+ * Context:
+ *     runtime, pageable
+ *     may be called after SK_INIT_IO
+ *
+ * Returns:
+ *     SK_ADDR_SUCCESS
+ *     SK_ADDR_ILLEGAL_PORT
+ */
+int    SkAddrPromiscuousChange(
+SK_AC  *pAC,                   /* adapter context */
+SK_IOC IoC,                    /* I/O context */
+SK_U32 PortNumber,             /* port whose promiscuous mode changes */
+int            NewPromMode)    /* new promiscuous mode */
+{
+       int ReturnCode = 0;
+#if (!defined(SK_SLIM) || defined(DEBUG))
+       if (PortNumber >= (SK_U32) pAC->GIni.GIMacsFound) {
+               return (SK_ADDR_ILLEGAL_PORT);
+       }
+#endif /* !SK_SLIM || DEBUG */
+
+#ifdef GENESIS
+       if (pAC->GIni.GIGenesis) {
+               ReturnCode =
+                       SkAddrXmacPromiscuousChange(pAC, IoC, PortNumber, NewPromMode);
+       }
+#endif /* GENESIS */
+#ifdef YUKON
+       if (!pAC->GIni.GIGenesis) {
+               ReturnCode =
+                       SkAddrGmacPromiscuousChange(pAC, IoC, PortNumber, NewPromMode);
+       }
+#endif /* YUKON */
+
+       return (ReturnCode);
+
+}      /* SkAddrPromiscuousChange */
+
+#ifdef GENESIS
+
+/******************************************************************************
+ *
+ *     SkAddrXmacPromiscuousChange - set promiscuous mode for given port
+ *
+ * Description:
+ *     This routine manages promiscuous mode:
+ *     - none
+ *     - all LLC frames
+ *     - all MC frames
+ *
+ * Context:
+ *     runtime, pageable
+ *     may be called after SK_INIT_IO
+ *
+ * Returns:
+ *     SK_ADDR_SUCCESS
+ *     SK_ADDR_ILLEGAL_PORT
+ */
+static int     SkAddrXmacPromiscuousChange(
+SK_AC  *pAC,                   /* adapter context */
+SK_IOC IoC,                    /* I/O context */
+SK_U32 PortNumber,             /* port whose promiscuous mode changes */
+int            NewPromMode)    /* new promiscuous mode */
+{
+       int                     i;
+       SK_BOOL         InexactModeBit;
+       SK_U8           Inexact;
+       SK_U8           HwInexact;
+       SK_FILTER64     HwInexactFilter;
+       SK_U16          LoMode;         /* Lower 16 bits of XMAC Mode Register. */
+       int                     CurPromMode = SK_PROM_MODE_NONE;
+
+       /* Read CurPromMode from Hardware. */
+       XM_IN16(IoC, PortNumber, XM_MODE, &LoMode);
+
+       if ((LoMode & XM_MD_ENA_PROM) != 0) {
+               /* Promiscuous mode! */
+               CurPromMode |= SK_PROM_MODE_LLC;
+       }
+       
+       for (Inexact = 0xFF, i = 0; i < 8; i++) {
+               Inexact &= pAC->Addr.Port[PortNumber].InexactFilter.Bytes[i];
+       }
+       if (Inexact == 0xFF) {
+               CurPromMode |= (pAC->Addr.Port[PortNumber].PromMode & SK_PROM_MODE_ALL_MC);
+       }
+       else {
+               /* Get InexactModeBit (bit XM_MD_ENA_HASH in mode register) */
+               XM_IN16(IoC, PortNumber, XM_MODE, &LoMode);
+               
+               InexactModeBit = (LoMode & XM_MD_ENA_HASH) != 0;
+
+               /* Read 64-bit hash register from XMAC */
+               XM_INHASH(IoC, PortNumber, XM_HSM, &HwInexactFilter.Bytes[0]);
+
+               for (HwInexact = 0xFF, i = 0; i < 8; i++) {
+                       HwInexact &= HwInexactFilter.Bytes[i];
+               }
+
+               if (InexactModeBit && (HwInexact == 0xFF)) {
+                       CurPromMode |= SK_PROM_MODE_ALL_MC;
+               }
+       }
+
+       pAC->Addr.Port[PortNumber].PromMode = NewPromMode;
+
+       if (NewPromMode == CurPromMode) {
+               return (SK_ADDR_SUCCESS);
+       }
+
+       if ((NewPromMode & SK_PROM_MODE_ALL_MC) &&
+               !(CurPromMode & SK_PROM_MODE_ALL_MC)) { /* All MC. */
+               
+               /* Set all bits in 64-bit hash register. */
+               XM_OUTHASH(IoC, PortNumber, XM_HSM, &OnesHash);
+
+               /* Enable Hashing */
+               SkMacHashing(pAC, IoC, (int) PortNumber, SK_TRUE);
+       }
+       else if ((CurPromMode & SK_PROM_MODE_ALL_MC) &&
+               !(NewPromMode & SK_PROM_MODE_ALL_MC)) { /* Norm MC. */
+               for (Inexact = 0, i = 0; i < 8; i++) {
+                       Inexact |= pAC->Addr.Port[PortNumber].InexactFilter.Bytes[i];
+               }
+               if (Inexact == 0) {
+                       /* Disable Hashing */
+                       SkMacHashing(pAC, IoC, (int) PortNumber, SK_FALSE);
+               }
+               else {
+                       /* Set 64-bit hash register to InexactFilter. */
+                       XM_OUTHASH(IoC, PortNumber, XM_HSM,
+                               &pAC->Addr.Port[PortNumber].InexactFilter.Bytes[0]);
+
+                       /* Enable Hashing */
+                       SkMacHashing(pAC, IoC, (int) PortNumber, SK_TRUE);
+               }
+       }
+
+       if ((NewPromMode & SK_PROM_MODE_LLC) &&
+               !(CurPromMode & SK_PROM_MODE_LLC)) {    /* Prom. LLC */
+               /* Set the MAC in Promiscuous Mode */
+               SkMacPromiscMode(pAC, IoC, (int) PortNumber, SK_TRUE);
+       }
+       else if ((CurPromMode & SK_PROM_MODE_LLC) &&
+               !(NewPromMode & SK_PROM_MODE_LLC)) {    /* Norm. LLC. */
+               /* Clear Promiscuous Mode */
+               SkMacPromiscMode(pAC, IoC, (int) PortNumber, SK_FALSE);
+       }
+       
+       return (SK_ADDR_SUCCESS);
+       
+}      /* SkAddrXmacPromiscuousChange */
+
+#endif /* GENESIS */
+
+#ifdef YUKON
+
+/******************************************************************************
+ *
+ *     SkAddrGmacPromiscuousChange - set promiscuous mode for given port
+ *
+ * Description:
+ *     This routine manages promiscuous mode:
+ *     - none
+ *     - all LLC frames
+ *     - all MC frames
+ *
+ * Context:
+ *     runtime, pageable
+ *     may be called after SK_INIT_IO
+ *
+ * Returns:
+ *     SK_ADDR_SUCCESS
+ *     SK_ADDR_ILLEGAL_PORT
+ */
+static int     SkAddrGmacPromiscuousChange(
+SK_AC  *pAC,                   /* adapter context */
+SK_IOC IoC,                    /* I/O context */
+SK_U32 PortNumber,             /* port whose promiscuous mode changes */
+int            NewPromMode)    /* new promiscuous mode */
+{
+       SK_U16          ReceiveControl; /* GMAC Receive Control Register */
+       int             CurPromMode = SK_PROM_MODE_NONE;
+
+       /* Read CurPromMode from Hardware. */
+       GM_IN16(IoC, PortNumber, GM_RX_CTRL, &ReceiveControl);
+
+       if ((ReceiveControl & (GM_RXCR_UCF_ENA | GM_RXCR_MCF_ENA)) == 0) {
+               /* Promiscuous mode! */
+               CurPromMode |= SK_PROM_MODE_LLC;
+       }
+
+       if ((ReceiveControl & GM_RXCR_MCF_ENA) == 0) {
+               /* All Multicast mode! */
+               CurPromMode |= (pAC->Addr.Port[PortNumber].PromMode & SK_PROM_MODE_ALL_MC);
+       }
+
+       pAC->Addr.Port[PortNumber].PromMode = NewPromMode;
+
+       if (NewPromMode == CurPromMode) {
+               return (SK_ADDR_SUCCESS);
+       }
+       
+       if ((NewPromMode & SK_PROM_MODE_ALL_MC) &&
+               !(CurPromMode & SK_PROM_MODE_ALL_MC)) { /* All MC */
+               
+               /* Set all bits in 64-bit hash register. */
+               GM_OUTHASH(IoC, PortNumber, GM_MC_ADDR_H1, &OnesHash);
+               
+               /* Enable Hashing */
+               SkMacHashing(pAC, IoC, (int) PortNumber, SK_TRUE);
+       }
+       
+       if ((CurPromMode & SK_PROM_MODE_ALL_MC) &&
+               !(NewPromMode & SK_PROM_MODE_ALL_MC)) { /* Norm. MC */
+
+               /* Set 64-bit hash register to InexactFilter. */
+               GM_OUTHASH(IoC, PortNumber, GM_MC_ADDR_H1,
+                       &pAC->Addr.Port[PortNumber].InexactFilter.Bytes[0]);
+
+               /* Enable Hashing. */
+               SkMacHashing(pAC, IoC, (int) PortNumber, SK_TRUE);
+       }
+
+       if ((NewPromMode & SK_PROM_MODE_LLC) &&
+               !(CurPromMode & SK_PROM_MODE_LLC)) {    /* Prom. LLC */
+               
+               /* Set the MAC to Promiscuous Mode. */
+               SkMacPromiscMode(pAC, IoC, (int) PortNumber, SK_TRUE);
+       }
+       else if ((CurPromMode & SK_PROM_MODE_LLC) &&
+               !(NewPromMode & SK_PROM_MODE_LLC)) {    /* Norm. LLC */
+               
+               /* Clear Promiscuous Mode. */
+               SkMacPromiscMode(pAC, IoC, (int) PortNumber, SK_FALSE);
+       }
+
+       return (SK_ADDR_SUCCESS);
+       
+}      /* SkAddrGmacPromiscuousChange */
+
+#endif /* YUKON */
+
+#ifndef SK_SLIM
+
+/******************************************************************************
+ *
+ *     SkAddrSwap - swap address info
+ *
+ * Description:
+ *     This routine swaps address info of two ports.
+ *
+ * Context:
+ *     runtime, pageable
+ *     may be called after SK_INIT_IO
+ *
+ * Returns:
+ *     SK_ADDR_SUCCESS
+ *     SK_ADDR_ILLEGAL_PORT
+ */
+int    SkAddrSwap(
+SK_AC  *pAC,                   /* adapter context */
+SK_IOC IoC,                    /* I/O context */
+SK_U32 FromPortNumber,         /* Port1 Index */
+SK_U32 ToPortNumber)           /* Port2 Index */
+{
+       int                     i;
+       SK_U8           Byte;
+       SK_MAC_ADDR     MacAddr;
+       SK_U32          DWord;
+
+       if (FromPortNumber >= (SK_U32) pAC->GIni.GIMacsFound) {
+               return (SK_ADDR_ILLEGAL_PORT);
+       }
+
+       if (ToPortNumber >= (SK_U32) pAC->GIni.GIMacsFound) {
+               return (SK_ADDR_ILLEGAL_PORT);
+       }
+
+       if (pAC->Rlmt.Port[FromPortNumber].Net != pAC->Rlmt.Port[ToPortNumber].Net) {
+               return (SK_ADDR_ILLEGAL_PORT);
+       }
+
+       /*
+        * Swap:
+        * - Exact Match Entries (GEnesis and Yukon)
+        *   Yukon uses first entry for the logical MAC
+        *   address (stored in the second GMAC register).
+        * - FirstExactMatchRlmt (GEnesis only)
+        * - NextExactMatchRlmt (GEnesis only)
+        * - FirstExactMatchDrv (GEnesis only)
+        * - NextExactMatchDrv (GEnesis only)
+        * - 64-bit filter (InexactFilter)
+        * - Promiscuous Mode
+        * of ports.
+        */
+
+       for (i = 0; i < SK_ADDR_EXACT_MATCHES; i++) {
+               MacAddr = pAC->Addr.Port[FromPortNumber].Exact[i];
+               pAC->Addr.Port[FromPortNumber].Exact[i] =
+                       pAC->Addr.Port[ToPortNumber].Exact[i];
+               pAC->Addr.Port[ToPortNumber].Exact[i] = MacAddr;
+       }
+
+       for (i = 0; i < 8; i++) {
+               Byte = pAC->Addr.Port[FromPortNumber].InexactFilter.Bytes[i];
+               pAC->Addr.Port[FromPortNumber].InexactFilter.Bytes[i] =
+                       pAC->Addr.Port[ToPortNumber].InexactFilter.Bytes[i];
+               pAC->Addr.Port[ToPortNumber].InexactFilter.Bytes[i] = Byte;
+       }
+       
+       i = pAC->Addr.Port[FromPortNumber].PromMode;
+       pAC->Addr.Port[FromPortNumber].PromMode = pAC->Addr.Port[ToPortNumber].PromMode;
+       pAC->Addr.Port[ToPortNumber].PromMode = i;
+       
+       if (pAC->GIni.GIGenesis) {
+               DWord = pAC->Addr.Port[FromPortNumber].FirstExactMatchRlmt;
+               pAC->Addr.Port[FromPortNumber].FirstExactMatchRlmt =
+                       pAC->Addr.Port[ToPortNumber].FirstExactMatchRlmt;
+               pAC->Addr.Port[ToPortNumber].FirstExactMatchRlmt = DWord;
+               
+               DWord = pAC->Addr.Port[FromPortNumber].NextExactMatchRlmt;
+               pAC->Addr.Port[FromPortNumber].NextExactMatchRlmt =
+                       pAC->Addr.Port[ToPortNumber].NextExactMatchRlmt;
+               pAC->Addr.Port[ToPortNumber].NextExactMatchRlmt = DWord;
+               
+               DWord = pAC->Addr.Port[FromPortNumber].FirstExactMatchDrv;
+               pAC->Addr.Port[FromPortNumber].FirstExactMatchDrv =
+                       pAC->Addr.Port[ToPortNumber].FirstExactMatchDrv;
+               pAC->Addr.Port[ToPortNumber].FirstExactMatchDrv = DWord;
+               
+               DWord = pAC->Addr.Port[FromPortNumber].NextExactMatchDrv;
+               pAC->Addr.Port[FromPortNumber].NextExactMatchDrv =
+                       pAC->Addr.Port[ToPortNumber].NextExactMatchDrv;
+               pAC->Addr.Port[ToPortNumber].NextExactMatchDrv = DWord;
+       }
+       
+       /* CAUTION: Solution works if only ports of one adapter are in use. */
+       for (i = 0; (SK_U32) i < pAC->Rlmt.Net[pAC->Rlmt.Port[ToPortNumber].
+               Net->NetNumber].NumPorts; i++) {
+               if (pAC->Rlmt.Net[pAC->Rlmt.Port[ToPortNumber].Net->NetNumber].
+                       Port[i]->PortNumber == ToPortNumber) {
+                       pAC->Addr.Net[pAC->Rlmt.Port[ToPortNumber].Net->NetNumber].
+                               ActivePort = i;
+                       /* 20001207 RA: Was "ToPortNumber;". */
+               }
+       }
+       
+       (void) SkAddrMcUpdate(pAC, IoC, FromPortNumber);
+       (void) SkAddrMcUpdate(pAC, IoC, ToPortNumber);
+
+       return (SK_ADDR_SUCCESS);
+       
+}      /* SkAddrSwap */
+
+#endif /* !SK_SLIM */
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
diff --git a/drivers/net/sk98lin/skdim.c b/drivers/net/sk98lin/skdim.c
new file mode 100644 (file)
index 0000000..37ce03f
--- /dev/null
@@ -0,0 +1,742 @@
+/******************************************************************************
+ *
+ * Name:       skdim.c
+ * Project:    GEnesis, PCI Gigabit Ethernet Adapter
+ * Version:    $Revision: 1.5 $
+ * Date:       $Date: 2003/11/28 12:55:40 $
+ * Purpose:    All functions to maintain interrupt moderation
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *     (C)Copyright 1998-2002 SysKonnect GmbH.
+ *     (C)Copyright 2002-2003 Marvell.
+ *
+ *     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.
+ *
+ *     The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * Description:
+ *
+ * This module is intended to manage the dynamic interrupt moderation on both   
+ * GEnesis and Yukon adapters.
+ *
+ * Include File Hierarchy:
+ *
+ *     "skdrv1st.h"
+ *     "skdrv2nd.h"
+ *
+ ******************************************************************************/
+
+#ifndef        lint
+static const char SysKonnectFileId[] =
+       "@(#) $Id: skdim.c,v 1.5 2003/11/28 12:55:40 rroesler Exp $ (C) SysKonnect.";
+#endif
+
+#define __SKADDR_C
+
+#ifdef __cplusplus
+#error C++ is not yet supported.
+extern "C" {
+#endif
+
+/*******************************************************************************
+**
+** Includes
+**
+*******************************************************************************/
+
+#ifndef __INC_SKDRV1ST_H
+#include "h/skdrv1st.h"
+#endif
+
+#ifndef __INC_SKDRV2ND_H
+#include "h/skdrv2nd.h"
+#endif
+
+#include       <linux/kernel_stat.h>
+
+/*******************************************************************************
+**
+** Defines
+**
+*******************************************************************************/
+
+/*******************************************************************************
+**
+** Typedefs
+**
+*******************************************************************************/
+
+/*******************************************************************************
+**
+** Local function prototypes 
+**
+*******************************************************************************/
+
+static unsigned int GetCurrentSystemLoad(SK_AC *pAC);
+static SK_U64       GetIsrCalls(SK_AC *pAC);
+static SK_BOOL      IsIntModEnabled(SK_AC *pAC);
+static void         SetCurrIntCtr(SK_AC *pAC);
+static void         EnableIntMod(SK_AC *pAC); 
+static void         DisableIntMod(SK_AC *pAC);
+static void         ResizeDimTimerDuration(SK_AC *pAC);
+static void         DisplaySelectedModerationType(SK_AC *pAC);
+static void         DisplaySelectedModerationMask(SK_AC *pAC);
+static void         DisplayDescrRatio(SK_AC *pAC);
+
+/*******************************************************************************
+**
+** Global variables
+**
+*******************************************************************************/
+
+/*******************************************************************************
+**
+** Local variables
+**
+*******************************************************************************/
+
+/*******************************************************************************
+**
+** Global functions 
+**
+*******************************************************************************/
+
+/*******************************************************************************
+** Function     : SkDimModerate
+** Description  : Called in every ISR to check if moderation is to be applied
+**                or not for the current number of interrupts
+** Programmer   : Ralph Roesler
+** Last Modified: 22-mar-03
+** Returns      : void (!)
+** Notes        : -
+*******************************************************************************/
+
+void 
+SkDimModerate(SK_AC *pAC) {
+    unsigned int CurrSysLoad    = 0;  /* expressed in percent */
+    unsigned int LoadIncrease   = 0;  /* expressed in percent */
+    SK_U64       ThresholdInts  = 0;
+    SK_U64       IsrCallsPerSec = 0;
+
+#define M_DIMINFO pAC->DynIrqModInfo
+
+    if (!IsIntModEnabled(pAC)) {
+        if (M_DIMINFO.IntModTypeSelect == C_INT_MOD_DYNAMIC) {
+            CurrSysLoad = GetCurrentSystemLoad(pAC);
+            if (CurrSysLoad > 75) {
+                    /* 
+                    ** More than 75% total system load! Enable the moderation 
+                    ** to shield the system against too many interrupts.
+                    */
+                    EnableIntMod(pAC);
+            } else if (CurrSysLoad > M_DIMINFO.PrevSysLoad) {
+                LoadIncrease = (CurrSysLoad - M_DIMINFO.PrevSysLoad);
+                if (LoadIncrease > ((M_DIMINFO.PrevSysLoad *
+                                         C_INT_MOD_ENABLE_PERCENTAGE) / 100)) {
+                    if (CurrSysLoad > 10) {
+                        /* 
+                        ** More than 50% increase with respect to the 
+                        ** previous load of the system. Most likely this 
+                        ** is due to our ISR-proc...
+                        */
+                        EnableIntMod(pAC);
+                    }
+                }
+            } else {
+                /*
+                ** Neither too much system load at all nor too much increase
+                ** with respect to the previous system load. Hence, we can leave
+                ** the ISR-handling like it is without enabling moderation.
+                */
+            }
+            M_DIMINFO.PrevSysLoad = CurrSysLoad;
+        }   
+    } else {
+        if (M_DIMINFO.IntModTypeSelect == C_INT_MOD_DYNAMIC) {
+            ThresholdInts  = ((M_DIMINFO.MaxModIntsPerSec *
+                                   C_INT_MOD_DISABLE_PERCENTAGE) / 100);
+            IsrCallsPerSec = GetIsrCalls(pAC);
+            if (IsrCallsPerSec <= ThresholdInts) {
+                /* 
+                ** The number of interrupts within the last second is 
+                ** lower than the disable_percentage of the desried 
+                ** maxrate. Therefore we can disable the moderation.
+                */
+                DisableIntMod(pAC);
+                M_DIMINFO.MaxModIntsPerSec = 
+                   (M_DIMINFO.MaxModIntsPerSecUpperLimit +
+                    M_DIMINFO.MaxModIntsPerSecLowerLimit) / 2;
+            } else {
+                /*
+                ** The number of interrupts per sec is the same as expected.
+                ** Evalulate the descriptor-ratio. If it has changed, a resize 
+                ** in the moderation timer might be useful
+                */
+                if (M_DIMINFO.AutoSizing) {
+                    ResizeDimTimerDuration(pAC);
+                }
+            }
+        }
+    }
+
+    /*
+    ** Some information to the log...
+    */
+    if (M_DIMINFO.DisplayStats) {
+        DisplaySelectedModerationType(pAC);
+        DisplaySelectedModerationMask(pAC);
+        DisplayDescrRatio(pAC);
+    }
+
+    M_DIMINFO.NbrProcessedDescr = 0; 
+    SetCurrIntCtr(pAC);
+}
+
+/*******************************************************************************
+** Function     : SkDimStartModerationTimer
+** Description  : Starts the audit-timer for the dynamic interrupt moderation
+** Programmer   : Ralph Roesler
+** Last Modified: 22-mar-03
+** Returns      : void (!)
+** Notes        : -
+*******************************************************************************/
+
+void 
+SkDimStartModerationTimer(SK_AC *pAC) {
+    SK_EVPARA    EventParam;   /* Event struct for timer event */
+    SK_MEMSET((char *) &EventParam, 0, sizeof(EventParam));
+    EventParam.Para32[0] = SK_DRV_MODERATION_TIMER;
+    SkTimerStart(pAC, pAC->IoBase, &pAC->DynIrqModInfo.ModTimer,
+                 SK_DRV_MODERATION_TIMER_LENGTH,
+                 SKGE_DRV, SK_DRV_TIMER, EventParam);
+}
+
+/*******************************************************************************
+** Function     : SkDimEnableModerationIfNeeded
+** Description  : Either enables or disables moderation
+** Programmer   : Ralph Roesler
+** Last Modified: 22-mar-03
+** Returns      : void (!)
+** Notes        : This function is called when a particular adapter is opened
+**                There is no Disable function, because when all interrupts 
+**                might be disable, the moderation timer has no meaning at all
+******************************************************************************/
+
+void
+SkDimEnableModerationIfNeeded(SK_AC *pAC) {
+
+    if (M_DIMINFO.IntModTypeSelect == C_INT_MOD_STATIC) {
+        EnableIntMod(pAC);   /* notification print in this function */
+    } else if (M_DIMINFO.IntModTypeSelect == C_INT_MOD_DYNAMIC) {
+        SkDimStartModerationTimer(pAC);
+        if (M_DIMINFO.DisplayStats) {
+            printk("Dynamic moderation has been enabled\n");
+        }
+    } else {
+        if (M_DIMINFO.DisplayStats) {
+            printk("No moderation has been enabled\n");
+        }
+    }
+}
+
+/*******************************************************************************
+** Function     : SkDimDisplayModerationSettings
+** Description  : Displays the current settings regarding interrupt moderation
+** Programmer   : Ralph Roesler
+** Last Modified: 22-mar-03
+** Returns      : void (!)
+** Notes        : -
+*******************************************************************************/
+
+void 
+SkDimDisplayModerationSettings(SK_AC *pAC) {
+    DisplaySelectedModerationType(pAC);
+    DisplaySelectedModerationMask(pAC);
+}
+
+/*******************************************************************************
+**
+** Local functions 
+**
+*******************************************************************************/
+
+/*******************************************************************************
+** Function     : GetCurrentSystemLoad
+** Description  : Retrieves the current system load of the system. This load
+**                is evaluated for all processors within the system.
+** Programmer   : Ralph Roesler
+** Last Modified: 22-mar-03
+** Returns      : unsigned int: load expressed in percentage
+** Notes        : The possible range being returned is from 0 up to 100.
+**                Whereas 0 means 'no load at all' and 100 'system fully loaded'
+**                It is impossible to determine what actually causes the system
+**                to be in 100%, but maybe that is due to too much interrupts.
+*******************************************************************************/
+
+static unsigned int
+GetCurrentSystemLoad(SK_AC *pAC) {
+       unsigned long jif         = jiffies;
+       unsigned int  UserTime    = 0;
+       unsigned int  SystemTime  = 0;
+       unsigned int  NiceTime    = 0;
+       unsigned int  IdleTime    = 0;
+       unsigned int  TotalTime   = 0;
+       unsigned int  UsedTime    = 0;
+       unsigned int  SystemLoad  = 0;
+
+       /* unsigned int  NbrCpu      = 0; */
+
+       /*
+       ** The following lines have been commented out, because
+       ** from kernel 2.5.44 onwards, the kernel-owned structure
+       **
+       **      struct kernel_stat kstat
+       **
+       ** is not marked as an exported symbol in the file
+       **
+       **      kernel/ksyms.c 
+       **
+       ** As a consequence, using this driver as KLM is not possible
+       ** and any access of the structure kernel_stat via the 
+       ** dedicated macros kstat_cpu(i).cpustat.xxx is to be avoided.
+       **
+       ** The kstat-information might be added again in future 
+       ** versions of the 2.5.xx kernel, but for the time being, 
+       ** number of interrupts will serve as indication how much 
+       ** load we currently have... 
+       **
+       ** for (NbrCpu = 0; NbrCpu < num_online_cpus(); NbrCpu++) {
+       **      UserTime   = UserTime   + kstat_cpu(NbrCpu).cpustat.user;
+       **      NiceTime   = NiceTime   + kstat_cpu(NbrCpu).cpustat.nice;
+       **      SystemTime = SystemTime + kstat_cpu(NbrCpu).cpustat.system;
+       ** }
+       */
+       SK_U64 ThresholdInts  = 0;
+       SK_U64 IsrCallsPerSec = 0;
+
+       ThresholdInts  = ((M_DIMINFO.MaxModIntsPerSec *
+                          C_INT_MOD_ENABLE_PERCENTAGE) + 100);
+       IsrCallsPerSec = GetIsrCalls(pAC);
+       if (IsrCallsPerSec >= ThresholdInts) {
+           /*
+           ** We do not know how much the real CPU-load is!
+           ** Return 80% as a default in order to activate DIM
+           */
+           SystemLoad = 80;
+           return (SystemLoad);  
+       } 
+
+       UsedTime  = UserTime + NiceTime + SystemTime;
+
+       IdleTime  = jif * num_online_cpus() - UsedTime;
+       TotalTime = UsedTime + IdleTime;
+
+       SystemLoad = ( 100 * (UsedTime  - M_DIMINFO.PrevUsedTime) ) /
+                                               (TotalTime - M_DIMINFO.PrevTotalTime);
+
+       if (M_DIMINFO.DisplayStats) {
+               printk("Current system load is: %u\n", SystemLoad);
+       }
+
+       M_DIMINFO.PrevTotalTime = TotalTime;
+       M_DIMINFO.PrevUsedTime  = UsedTime;
+
+       return (SystemLoad);
+}
+
+/*******************************************************************************
+** Function     : GetIsrCalls
+** Description  : Depending on the selected moderation mask, this function will
+**                return the number of interrupts handled in the previous time-
+**                frame. This evaluated number is based on the current number 
+**                of interrupts stored in PNMI-context and the previous stored 
+**                interrupts.
+** Programmer   : Ralph Roesler
+** Last Modified: 23-mar-03
+** Returns      : int:   the number of interrupts being executed in the last
+**                       timeframe
+** Notes        : It makes only sense to call this function, when dynamic 
+**                interrupt moderation is applied
+*******************************************************************************/
+
+static SK_U64
+GetIsrCalls(SK_AC *pAC) {
+    SK_U64   RxPort0IntDiff = 0;
+    SK_U64   RxPort1IntDiff = 0;
+    SK_U64   TxPort0IntDiff = 0;
+    SK_U64   TxPort1IntDiff = 0;
+
+    if (pAC->DynIrqModInfo.MaskIrqModeration == IRQ_MASK_TX_ONLY) {
+        if (pAC->GIni.GIMacsFound == 2) {
+            TxPort1IntDiff = pAC->Pnmi.Port[1].TxIntrCts - 
+                             pAC->DynIrqModInfo.PrevPort1TxIntrCts;
+        }
+        TxPort0IntDiff = pAC->Pnmi.Port[0].TxIntrCts - 
+                         pAC->DynIrqModInfo.PrevPort0TxIntrCts;
+    } else if (pAC->DynIrqModInfo.MaskIrqModeration == IRQ_MASK_RX_ONLY) {
+        if (pAC->GIni.GIMacsFound == 2) {
+            RxPort1IntDiff = pAC->Pnmi.Port[1].RxIntrCts - 
+                             pAC->DynIrqModInfo.PrevPort1RxIntrCts;
+        }
+        RxPort0IntDiff = pAC->Pnmi.Port[0].RxIntrCts - 
+                         pAC->DynIrqModInfo.PrevPort0RxIntrCts;
+    } else {
+        if (pAC->GIni.GIMacsFound == 2) {
+            RxPort1IntDiff = pAC->Pnmi.Port[1].RxIntrCts - 
+                             pAC->DynIrqModInfo.PrevPort1RxIntrCts;
+            TxPort1IntDiff = pAC->Pnmi.Port[1].TxIntrCts - 
+                             pAC->DynIrqModInfo.PrevPort1TxIntrCts;
+        } 
+        RxPort0IntDiff = pAC->Pnmi.Port[0].RxIntrCts - 
+                         pAC->DynIrqModInfo.PrevPort0RxIntrCts;
+        TxPort0IntDiff = pAC->Pnmi.Port[0].TxIntrCts - 
+                         pAC->DynIrqModInfo.PrevPort0TxIntrCts;
+    }
+
+    return (RxPort0IntDiff + RxPort1IntDiff + TxPort0IntDiff + TxPort1IntDiff);
+}
+
+/*******************************************************************************
+** Function     : GetRxCalls
+** Description  : This function will return the number of times a receive inter-
+**                rupt was processed. This is needed to evaluate any resizing 
+**                factor.
+** Programmer   : Ralph Roesler
+** Last Modified: 23-mar-03
+** Returns      : SK_U64: the number of RX-ints being processed
+** Notes        : It makes only sense to call this function, when dynamic 
+**                interrupt moderation is applied
+*******************************************************************************/
+
+static SK_U64
+GetRxCalls(SK_AC *pAC) {
+    SK_U64   RxPort0IntDiff = 0;
+    SK_U64   RxPort1IntDiff = 0;
+
+    if (pAC->GIni.GIMacsFound == 2) {
+        RxPort1IntDiff = pAC->Pnmi.Port[1].RxIntrCts - 
+                         pAC->DynIrqModInfo.PrevPort1RxIntrCts;
+    }
+    RxPort0IntDiff = pAC->Pnmi.Port[0].RxIntrCts - 
+                     pAC->DynIrqModInfo.PrevPort0RxIntrCts;
+
+    return (RxPort0IntDiff + RxPort1IntDiff);
+}
+
+/*******************************************************************************
+** Function     : SetCurrIntCtr
+** Description  : Will store the current number orf occured interrupts in the 
+**                adapter context. This is needed to evaluated the number of 
+**                interrupts within a current timeframe.
+** Programmer   : Ralph Roesler
+** Last Modified: 23-mar-03
+** Returns      : void (!)
+** Notes        : -
+*******************************************************************************/
+
+static void
+SetCurrIntCtr(SK_AC *pAC) {
+    if (pAC->GIni.GIMacsFound == 2) {
+        pAC->DynIrqModInfo.PrevPort1RxIntrCts = pAC->Pnmi.Port[1].RxIntrCts;
+        pAC->DynIrqModInfo.PrevPort1TxIntrCts = pAC->Pnmi.Port[1].TxIntrCts;
+    } 
+    pAC->DynIrqModInfo.PrevPort0RxIntrCts = pAC->Pnmi.Port[0].RxIntrCts;
+    pAC->DynIrqModInfo.PrevPort0TxIntrCts = pAC->Pnmi.Port[0].TxIntrCts;
+}
+
+/*******************************************************************************
+** Function     : IsIntModEnabled()
+** Description  : Retrieves the current value of the interrupts moderation
+**                command register. Its content determines whether any 
+**                moderation is running or not.
+** Programmer   : Ralph Roesler
+** Last Modified: 23-mar-03
+** Returns      : SK_TRUE  : if mod timer running
+**                SK_FALSE : if no moderation is being performed
+** Notes        : -
+*******************************************************************************/
+
+static SK_BOOL
+IsIntModEnabled(SK_AC *pAC) {
+    unsigned long CtrCmd;
+
+    SK_IN32(pAC->IoBase, B2_IRQM_CTRL, &CtrCmd);
+    if ((CtrCmd & TIM_START) == TIM_START) {
+       return SK_TRUE;
+    } else {
+       return SK_FALSE;
+    }
+}
+
+/*******************************************************************************
+** Function     : EnableIntMod()
+** Description  : Enables the interrupt moderation using the values stored in
+**                in the pAC->DynIntMod data structure
+** Programmer   : Ralph Roesler
+** Last Modified: 22-mar-03
+** Returns      : -
+** Notes        : -
+*******************************************************************************/
+
+static void
+EnableIntMod(SK_AC *pAC) {
+    unsigned long ModBase;
+
+    if (pAC->GIni.GIChipId == CHIP_ID_GENESIS) {
+       ModBase = C_CLK_FREQ_GENESIS / pAC->DynIrqModInfo.MaxModIntsPerSec;
+    } else {
+       ModBase = C_CLK_FREQ_YUKON / pAC->DynIrqModInfo.MaxModIntsPerSec;
+    }
+
+    SK_OUT32(pAC->IoBase, B2_IRQM_INI,  ModBase);
+    SK_OUT32(pAC->IoBase, B2_IRQM_MSK,  pAC->DynIrqModInfo.MaskIrqModeration);
+    SK_OUT32(pAC->IoBase, B2_IRQM_CTRL, TIM_START);
+    if (M_DIMINFO.DisplayStats) {
+        printk("Enabled interrupt moderation (%i ints/sec)\n",
+               M_DIMINFO.MaxModIntsPerSec);
+    }
+}
+
+/*******************************************************************************
+** Function     : DisableIntMod()
+** Description  : Disables the interrupt moderation independent of what inter-
+**                rupts are running or not
+** Programmer   : Ralph Roesler
+** Last Modified: 23-mar-03
+** Returns      : -
+** Notes        : -
+*******************************************************************************/
+
+static void 
+DisableIntMod(SK_AC *pAC) {
+
+    SK_OUT32(pAC->IoBase, B2_IRQM_CTRL, TIM_STOP);
+    if (M_DIMINFO.DisplayStats) {
+        printk("Disabled interrupt moderation\n");
+    }
+} 
+
+/*******************************************************************************
+** Function     : ResizeDimTimerDuration();
+** Description  : Checks the current used descriptor ratio and resizes the 
+**                duration timer (longer/smaller) if possible. 
+** Programmer   : Ralph Roesler
+** Last Modified: 23-mar-03
+** Returns      : -
+** Notes        : There are both maximum and minimum timer duration value. 
+**                This function assumes that interrupt moderation is already
+**                enabled!
+*******************************************************************************/
+
+static void 
+ResizeDimTimerDuration(SK_AC *pAC) {
+    SK_BOOL IncreaseTimerDuration;
+    int     TotalMaxNbrDescr;
+    int     UsedDescrRatio;
+    int     RatioDiffAbs;
+    int     RatioDiffRel;
+    int     NewMaxModIntsPerSec;
+    int     ModAdjValue;
+    long    ModBase;
+
+    /*
+    ** Check first if we are allowed to perform any modification
+    */
+    if (IsIntModEnabled(pAC)) { 
+        if (M_DIMINFO.IntModTypeSelect != C_INT_MOD_DYNAMIC) {
+            return; 
+        } else {
+            if (M_DIMINFO.ModJustEnabled) {
+                M_DIMINFO.ModJustEnabled = SK_FALSE;
+                return;
+            }
+        }
+    }
+
+    /*
+    ** If we got until here, we have to evaluate the amount of the
+    ** descriptor ratio change...
+    */
+    TotalMaxNbrDescr = pAC->RxDescrPerRing * GetRxCalls(pAC);
+    UsedDescrRatio   = (M_DIMINFO.NbrProcessedDescr * 100) / TotalMaxNbrDescr;
+
+    if (UsedDescrRatio > M_DIMINFO.PrevUsedDescrRatio) {
+        RatioDiffAbs = (UsedDescrRatio - M_DIMINFO.PrevUsedDescrRatio);
+        RatioDiffRel = (RatioDiffAbs * 100) / UsedDescrRatio;
+        M_DIMINFO.PrevUsedDescrRatio = UsedDescrRatio;
+        IncreaseTimerDuration = SK_FALSE;  /* in other words: DECREASE */
+    } else if (UsedDescrRatio < M_DIMINFO.PrevUsedDescrRatio) {
+        RatioDiffAbs = (M_DIMINFO.PrevUsedDescrRatio - UsedDescrRatio);
+        RatioDiffRel = (RatioDiffAbs * 100) / M_DIMINFO.PrevUsedDescrRatio;
+        M_DIMINFO.PrevUsedDescrRatio = UsedDescrRatio;
+        IncreaseTimerDuration = SK_TRUE;   /* in other words: INCREASE */
+    } else {
+        RatioDiffAbs = (M_DIMINFO.PrevUsedDescrRatio - UsedDescrRatio);
+        RatioDiffRel = (RatioDiffAbs * 100) / M_DIMINFO.PrevUsedDescrRatio;
+        M_DIMINFO.PrevUsedDescrRatio = UsedDescrRatio;
+        IncreaseTimerDuration = SK_TRUE;   /* in other words: INCREASE */
+    }
+
+    /*
+    ** Now we can determine the change in percent
+    */
+    if ((RatioDiffRel >= 0) && (RatioDiffRel <= 5) ) {
+       ModAdjValue = 1;  /*  1% change - maybe some other value in future */
+    } else if ((RatioDiffRel > 5) && (RatioDiffRel <= 10) ) {
+       ModAdjValue = 1;  /*  1% change - maybe some other value in future */
+    } else if ((RatioDiffRel > 10) && (RatioDiffRel <= 15) ) {
+       ModAdjValue = 1;  /*  1% change - maybe some other value in future */
+    } else {
+       ModAdjValue = 1;  /*  1% change - maybe some other value in future */
+    }
+
+    if (IncreaseTimerDuration) {
+       NewMaxModIntsPerSec =  M_DIMINFO.MaxModIntsPerSec +
+                             (M_DIMINFO.MaxModIntsPerSec * ModAdjValue) / 100;
+    } else {
+       NewMaxModIntsPerSec =  M_DIMINFO.MaxModIntsPerSec -
+                             (M_DIMINFO.MaxModIntsPerSec * ModAdjValue) / 100;
+    }
+
+    /* 
+    ** Check if we exceed boundaries...
+    */
+    if ( (NewMaxModIntsPerSec > M_DIMINFO.MaxModIntsPerSecUpperLimit) ||
+         (NewMaxModIntsPerSec < M_DIMINFO.MaxModIntsPerSecLowerLimit)) {
+        if (M_DIMINFO.DisplayStats) {
+            printk("Cannot change ModTim from %i to %i ints/sec\n",
+                   M_DIMINFO.MaxModIntsPerSec, NewMaxModIntsPerSec);
+        }
+        return;
+    } else {
+        if (M_DIMINFO.DisplayStats) {
+            printk("Resized ModTim from %i to %i ints/sec\n",
+                   M_DIMINFO.MaxModIntsPerSec, NewMaxModIntsPerSec);
+        }
+    }
+
+    M_DIMINFO.MaxModIntsPerSec = NewMaxModIntsPerSec;
+
+    if (pAC->GIni.GIChipId == CHIP_ID_GENESIS) {
+        ModBase = C_CLK_FREQ_GENESIS / pAC->DynIrqModInfo.MaxModIntsPerSec;
+    } else {
+        ModBase = C_CLK_FREQ_YUKON / pAC->DynIrqModInfo.MaxModIntsPerSec;
+    }
+
+    /* 
+    ** We do not need to touch any other registers
+    */
+    SK_OUT32(pAC->IoBase, B2_IRQM_INI, ModBase);
+} 
+
+/*******************************************************************************
+** Function     : DisplaySelectedModerationType()
+** Description  : Displays what type of moderation we have
+** Programmer   : Ralph Roesler
+** Last Modified: 23-mar-03
+** Returns      : void!
+** Notes        : -
+*******************************************************************************/
+
+static void
+DisplaySelectedModerationType(SK_AC *pAC) {
+
+    if (pAC->DynIrqModInfo.DisplayStats) {
+        if (pAC->DynIrqModInfo.IntModTypeSelect == C_INT_MOD_STATIC) {
+             printk("Static int moderation runs with %i INTS/sec\n",
+                    pAC->DynIrqModInfo.MaxModIntsPerSec);
+        } else if (pAC->DynIrqModInfo.IntModTypeSelect == C_INT_MOD_DYNAMIC) {
+             if (IsIntModEnabled(pAC)) {
+                printk("Dynamic int moderation runs with %i INTS/sec\n",
+                       pAC->DynIrqModInfo.MaxModIntsPerSec);
+             } else {
+                printk("Dynamic int moderation currently not applied\n");
+             }
+        } else {
+             printk("No interrupt moderation selected!\n");
+        }
+    }
+}
+
+/*******************************************************************************
+** Function     : DisplaySelectedModerationMask()
+** Description  : Displays what interrupts are moderated
+** Programmer   : Ralph Roesler
+** Last Modified: 23-mar-03
+** Returns      : void!
+** Notes        : -
+*******************************************************************************/
+
+static void
+DisplaySelectedModerationMask(SK_AC *pAC) {
+
+    if (pAC->DynIrqModInfo.DisplayStats) {
+        if (pAC->DynIrqModInfo.IntModTypeSelect != C_INT_MOD_NONE) {
+            switch (pAC->DynIrqModInfo.MaskIrqModeration) {
+                case IRQ_MASK_TX_ONLY: 
+                   printk("Only Tx-interrupts are moderated\n");
+                   break;
+                case IRQ_MASK_RX_ONLY: 
+                   printk("Only Rx-interrupts are moderated\n");
+                   break;
+                case IRQ_MASK_SP_ONLY: 
+                   printk("Only special-interrupts are moderated\n");
+                   break;
+                case IRQ_MASK_TX_RX: 
+                   printk("Tx- and Rx-interrupts are moderated\n");
+                   break;
+                case IRQ_MASK_SP_RX: 
+                   printk("Special- and Rx-interrupts are moderated\n");
+                   break;
+                case IRQ_MASK_SP_TX: 
+                   printk("Special- and Tx-interrupts are moderated\n");
+                   break;
+                case IRQ_MASK_RX_TX_SP:
+                   printk("All Rx-, Tx and special-interrupts are moderated\n");
+                   break;
+                default:
+                   printk("Don't know what is moderated\n");
+                   break;
+            }
+        } else {
+            printk("No specific interrupts masked for moderation\n");
+        }
+    } 
+}
+
+/*******************************************************************************
+** Function     : DisplayDescrRatio
+** Description  : Like the name states...
+** Programmer   : Ralph Roesler
+** Last Modified: 23-mar-03
+** Returns      : void!
+** Notes        : -
+*******************************************************************************/
+
+static void
+DisplayDescrRatio(SK_AC *pAC) {
+    int TotalMaxNbrDescr = 0;
+
+    if (pAC->DynIrqModInfo.DisplayStats) {
+        TotalMaxNbrDescr = pAC->RxDescrPerRing * GetRxCalls(pAC);
+        printk("Ratio descriptors: %i/%i\n",
+               M_DIMINFO.NbrProcessedDescr, TotalMaxNbrDescr);
+    }
+}
+
+/*******************************************************************************
+**
+** End of file
+**
+*******************************************************************************/
diff --git a/drivers/net/sk98lin/skethtool.c b/drivers/net/sk98lin/skethtool.c
new file mode 100644 (file)
index 0000000..5a6da89
--- /dev/null
@@ -0,0 +1,627 @@
+/******************************************************************************
+ *
+ * Name:        skethtool.c
+ * Project:     GEnesis, PCI Gigabit Ethernet Adapter
+ * Version:     $Revision: 1.7 $
+ * Date:        $Date: 2004/09/29 13:32:07 $
+ * Purpose:     All functions regarding ethtool handling
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *     (C)Copyright 1998-2002 SysKonnect GmbH.
+ *     (C)Copyright 2002-2004 Marvell.
+ *
+ *     Driver for Marvell Yukon/2 chipset and SysKonnect Gigabit Ethernet 
+ *      Server Adapters.
+ *
+ *     Author: Ralph Roesler (rroesler@syskonnect.de)
+ *             Mirko Lindner (mlindner@syskonnect.de)
+ *
+ *     Address all question to: linux@syskonnect.de
+ *
+ *     The technical manual for the adapters is available from SysKonnect's
+ *     web pages: www.syskonnect.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.
+ *
+ *     The information in this file is provided "AS IS" without warranty.
+ *
+ *****************************************************************************/
+
+#include "h/skdrv1st.h"
+#include "h/skdrv2nd.h"
+#include "h/skversion.h"
+
+#include <linux/ethtool.h>
+#include <linux/timer.h>
+#include <linux/delay.h>
+
+/******************************************************************************
+ *
+ * Defines
+ *
+ *****************************************************************************/
+
+#define SUPP_COPPER_ALL (SUPPORTED_10baseT_Half  | SUPPORTED_10baseT_Full  | \
+                         SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full | \
+                         SUPPORTED_1000baseT_Half| SUPPORTED_1000baseT_Full| \
+                         SUPPORTED_TP)
+
+#define ADV_COPPER_ALL  (ADVERTISED_10baseT_Half  | ADVERTISED_10baseT_Full  | \
+                         ADVERTISED_100baseT_Half | ADVERTISED_100baseT_Full | \
+                         ADVERTISED_1000baseT_Half| ADVERTISED_1000baseT_Full| \
+                         ADVERTISED_TP)
+
+#define SUPP_FIBRE_ALL  (SUPPORTED_1000baseT_Full | \
+                         SUPPORTED_FIBRE          | \
+                         SUPPORTED_Autoneg)
+
+#define ADV_FIBRE_ALL   (ADVERTISED_1000baseT_Full | \
+                         ADVERTISED_FIBRE          | \
+                         ADVERTISED_Autoneg)
+
+
+/******************************************************************************
+ *
+ * Local Functions
+ *
+ *****************************************************************************/
+
+/*****************************************************************************
+ *
+ *     getSettings - retrieves the current settings of the selected adapter
+ *
+ * Description:
+ *     The current configuration of the selected adapter is returned.
+ *     This configuration involves a)speed, b)duplex and c)autoneg plus
+ *     a number of other variables.
+ *
+ * Returns:    always 0
+ *
+ */
+static int getSettings(struct net_device *dev, struct ethtool_cmd *ecmd)
+{
+       const DEV_NET *pNet = netdev_priv(dev);
+       int port = pNet->PortNr;
+       const SK_AC *pAC = pNet->pAC;
+       const SK_GEPORT *pPort = &pAC->GIni.GP[port];
+
+       static int DuplexAutoNegConfMap[9][3]= {
+               { -1                     , -1         , -1              },
+               { 0                      , -1         , -1              },
+               { SK_LMODE_HALF          , DUPLEX_HALF, AUTONEG_DISABLE },
+               { SK_LMODE_FULL          , DUPLEX_FULL, AUTONEG_DISABLE },
+               { SK_LMODE_AUTOHALF      , DUPLEX_HALF, AUTONEG_ENABLE  },
+               { SK_LMODE_AUTOFULL      , DUPLEX_FULL, AUTONEG_ENABLE  },
+               { SK_LMODE_AUTOBOTH      , DUPLEX_FULL, AUTONEG_ENABLE  },
+               { SK_LMODE_AUTOSENSE     , -1         , -1              },
+               { SK_LMODE_INDETERMINATED, -1         , -1              }
+       };
+       static int SpeedConfMap[6][2] = {
+               { 0                       , -1         },
+               { SK_LSPEED_AUTO          , -1         },
+               { SK_LSPEED_10MBPS        , SPEED_10   },
+               { SK_LSPEED_100MBPS       , SPEED_100  },
+               { SK_LSPEED_1000MBPS      , SPEED_1000 },
+               { SK_LSPEED_INDETERMINATED, -1         }
+       };
+       static int AdvSpeedMap[6][2] = {
+               { 0                       , -1         },
+               { SK_LSPEED_AUTO          , -1         },
+               { SK_LSPEED_10MBPS        , ADVERTISED_10baseT_Half   | ADVERTISED_10baseT_Full },
+               { SK_LSPEED_100MBPS       , ADVERTISED_100baseT_Half  | ADVERTISED_100baseT_Full },
+               { SK_LSPEED_1000MBPS      , ADVERTISED_1000baseT_Half | ADVERTISED_1000baseT_Full},
+               { SK_LSPEED_INDETERMINATED, -1         }
+       };
+
+       ecmd->phy_address = port;
+       ecmd->speed       = SpeedConfMap[pPort->PLinkSpeedUsed][1];
+       ecmd->duplex      = DuplexAutoNegConfMap[pPort->PLinkModeStatus][1];
+       ecmd->autoneg     = DuplexAutoNegConfMap[pPort->PLinkModeStatus][2];
+       ecmd->transceiver = XCVR_INTERNAL;
+
+       if (pAC->GIni.GICopperType) {
+               ecmd->port        = PORT_TP;
+               ecmd->supported   = (SUPP_COPPER_ALL|SUPPORTED_Autoneg);
+               if (pAC->GIni.GIGenesis) {
+                       ecmd->supported &= ~(SUPPORTED_10baseT_Half);
+                       ecmd->supported &= ~(SUPPORTED_10baseT_Full);
+                       ecmd->supported &= ~(SUPPORTED_100baseT_Half);
+                       ecmd->supported &= ~(SUPPORTED_100baseT_Full);
+               } else {
+                       if (pAC->GIni.GIChipId == CHIP_ID_YUKON) {
+                               ecmd->supported &= ~(SUPPORTED_1000baseT_Half);
+                       } 
+#ifdef CHIP_ID_YUKON_FE
+                       if (pAC->GIni.GIChipId == CHIP_ID_YUKON_FE) {
+                               ecmd->supported &= ~(SUPPORTED_1000baseT_Half);
+                               ecmd->supported &= ~(SUPPORTED_1000baseT_Full);
+                       }
+#endif
+               }
+               if (pAC->GIni.GP[0].PLinkSpeed != SK_LSPEED_AUTO) {
+                       ecmd->advertising = AdvSpeedMap[pPort->PLinkSpeed][1];
+                       if (pAC->GIni.GIChipId == CHIP_ID_YUKON) {
+                               ecmd->advertising &= ~(SUPPORTED_1000baseT_Half);
+                       } 
+               } else {
+                       ecmd->advertising = ecmd->supported;
+               }
+
+               if (ecmd->autoneg == AUTONEG_ENABLE) 
+                       ecmd->advertising |= ADVERTISED_Autoneg;
+       } else {
+               ecmd->port        = PORT_FIBRE;
+               ecmd->supported   = SUPP_FIBRE_ALL;
+               ecmd->advertising = ADV_FIBRE_ALL;
+       }
+       return 0;
+}
+
+/*
+ * MIB infrastructure uses instance value starting at 1
+ * based on board and port.
+ */
+static inline u32 pnmiInstance(const DEV_NET *pNet)
+{
+       return 1 + (pNet->pAC->RlmtNets == 2) + pNet->PortNr;
+}
+
+/*****************************************************************************
+ *
+ *     setSettings - configures the settings of a selected adapter
+ *
+ * Description:
+ *     Possible settings that may be altered are a)speed, b)duplex or 
+ *     c)autonegotiation.
+ *
+ * Returns:
+ *     0:      everything fine, no error
+ *     <0:     the return value is the error code of the failure 
+ */
+static int setSettings(struct net_device *dev, struct ethtool_cmd *ecmd)
+{
+       DEV_NET *pNet = netdev_priv(dev);
+       SK_AC *pAC = pNet->pAC;
+       u32 instance;
+       char buf[4];
+       int len = 1;
+
+       if (ecmd->speed != SPEED_10 && ecmd->speed != SPEED_100 
+           && ecmd->speed != SPEED_1000)
+               return -EINVAL;
+
+       if (ecmd->duplex != DUPLEX_HALF && ecmd->duplex != DUPLEX_FULL)
+               return -EINVAL;
+
+       if (ecmd->autoneg != AUTONEG_DISABLE && ecmd->autoneg != AUTONEG_ENABLE)
+               return -EINVAL;
+
+       if (ecmd->autoneg == AUTONEG_DISABLE)
+               *buf = (ecmd->duplex == DUPLEX_FULL) 
+                       ? SK_LMODE_FULL : SK_LMODE_HALF;
+       else
+               *buf = (ecmd->duplex == DUPLEX_FULL) 
+                       ? SK_LMODE_AUTOFULL : SK_LMODE_AUTOHALF;
+       
+       instance = pnmiInstance(pNet);
+       if (SkPnmiSetVar(pAC, pAC->IoBase, OID_SKGE_LINK_MODE, 
+                          &buf, &len, instance, pNet->NetNr) != SK_PNMI_ERR_OK)
+               return -EINVAL;
+
+       switch(ecmd->speed) {
+       case SPEED_1000:
+               *buf = SK_LSPEED_1000MBPS;
+               break;
+       case SPEED_100:
+               *buf = SK_LSPEED_100MBPS;
+               break;
+       case SPEED_10:
+               *buf = SK_LSPEED_10MBPS;
+       }
+
+       if (SkPnmiSetVar(pAC, pAC->IoBase, OID_SKGE_SPEED_MODE, 
+                        &buf, &len, instance, pNet->NetNr) != SK_PNMI_ERR_OK)
+               return -EINVAL;
+
+       return 0;
+}
+
+/*****************************************************************************
+ *
+ *     getDriverInfo - returns generic driver and adapter information
+ *
+ * Description:
+ *     Generic driver information is returned via this function, such as
+ *     the name of the driver, its version and and firmware version.
+ *     In addition to this, the location of the selected adapter is 
+ *     returned as a bus info string (e.g. '01:05.0').
+ *     
+ * Returns:    N/A
+ *
+ */
+static void getDriverInfo(struct net_device *dev, struct ethtool_drvinfo *info)
+{
+       const DEV_NET   *pNet = netdev_priv(dev);
+       const SK_AC *pAC = pNet->pAC;
+       char vers[32];
+
+       snprintf(vers, sizeof(vers)-1, VER_STRING "(v%d.%d)",
+               (pAC->GIni.GIPciHwRev >> 4) & 0xf, pAC->GIni.GIPciHwRev & 0xf);
+
+       strlcpy(info->driver, DRIVER_FILE_NAME, sizeof(info->driver));
+       strcpy(info->version, vers);
+       strcpy(info->fw_version, "N/A");
+       strlcpy(info->bus_info, pci_name(pAC->PciDev), ETHTOOL_BUSINFO_LEN);
+}
+
+/*
+ * Ethtool statistics support.
+ */
+static const char StringsStats[][ETH_GSTRING_LEN] = {
+       "rx_packets",   "tx_packets",
+       "rx_bytes",     "tx_bytes",
+       "rx_errors",    "tx_errors",    
+       "rx_dropped",   "tx_dropped",
+       "multicasts",   "collisions",   
+       "rx_length_errors",             "rx_buffer_overflow_errors",
+       "rx_crc_errors",                "rx_frame_errors",
+       "rx_too_short_errors",          "rx_too_long_errors",
+       "rx_carrier_extension_errors",  "rx_symbol_errors",
+       "rx_llc_mac_size_errors",       "rx_carrier_errors",    
+       "rx_jabber_errors",             "rx_missed_errors",
+       "tx_abort_collision_errors",    "tx_carrier_errors",
+       "tx_buffer_underrun_errors",    "tx_heartbeat_errors",
+       "tx_window_errors",
+};
+
+static int getStatsCount(struct net_device *dev)
+{
+       return ARRAY_SIZE(StringsStats);
+}
+
+static void getStrings(struct net_device *dev, u32 stringset, u8 *data)
+{
+       switch(stringset) {
+       case ETH_SS_STATS:
+               memcpy(data, *StringsStats, sizeof(StringsStats));
+               break;
+       }
+}
+
+static void getEthtoolStats(struct net_device *dev,
+                           struct ethtool_stats *stats, u64 *data)
+{
+       const DEV_NET   *pNet = netdev_priv(dev);
+       const SK_AC *pAC = pNet->pAC;
+       const SK_PNMI_STRUCT_DATA *pPnmiStruct = &pAC->PnmiStruct;
+
+       *data++ = pPnmiStruct->Stat[0].StatRxOkCts;
+       *data++ = pPnmiStruct->Stat[0].StatTxOkCts;
+       *data++ = pPnmiStruct->Stat[0].StatRxOctetsOkCts;
+       *data++ = pPnmiStruct->Stat[0].StatTxOctetsOkCts;
+       *data++ = pPnmiStruct->InErrorsCts;
+       *data++ = pPnmiStruct->Stat[0].StatTxSingleCollisionCts;
+       *data++ = pPnmiStruct->RxNoBufCts;
+       *data++ = pPnmiStruct->TxNoBufCts;
+       *data++ = pPnmiStruct->Stat[0].StatRxMulticastOkCts;
+       *data++ = pPnmiStruct->Stat[0].StatTxSingleCollisionCts;
+       *data++ = pPnmiStruct->Stat[0].StatRxRuntCts;
+       *data++ = pPnmiStruct->Stat[0].StatRxFifoOverflowCts;
+       *data++ = pPnmiStruct->Stat[0].StatRxFcsCts;
+       *data++ = pPnmiStruct->Stat[0].StatRxFramingCts;
+       *data++ = pPnmiStruct->Stat[0].StatRxShortsCts;
+       *data++ = pPnmiStruct->Stat[0].StatRxTooLongCts;
+       *data++ = pPnmiStruct->Stat[0].StatRxCextCts;
+       *data++ = pPnmiStruct->Stat[0].StatRxSymbolCts;
+       *data++ = pPnmiStruct->Stat[0].StatRxIRLengthCts;
+       *data++ = pPnmiStruct->Stat[0].StatRxCarrierCts;
+       *data++ = pPnmiStruct->Stat[0].StatRxJabberCts;
+       *data++ = pPnmiStruct->Stat[0].StatRxMissedCts;
+       *data++ = pAC->stats.tx_aborted_errors;
+       *data++ = pPnmiStruct->Stat[0].StatTxCarrierCts;
+       *data++ = pPnmiStruct->Stat[0].StatTxFifoUnderrunCts;
+       *data++ = pPnmiStruct->Stat[0].StatTxCarrierCts;
+       *data++ = pAC->stats.tx_window_errors;
+}
+
+
+/*****************************************************************************
+ *
+ *     toggleLeds - Changes the LED state of an adapter
+ *
+ * Description:
+ *     This function changes the current state of all LEDs of an adapter so
+ *     that it can be located by a user. 
+ *
+ * Returns:    N/A
+ *
+ */
+static void toggleLeds(DEV_NET *pNet, int on)
+{
+       SK_AC *pAC = pNet->pAC;
+       int port = pNet->PortNr;
+       void __iomem *io = pAC->IoBase;
+
+       if (pAC->GIni.GIGenesis) {
+               SK_OUT8(io, MR_ADDR(port,LNK_LED_REG), 
+                       on ? SK_LNK_ON : SK_LNK_OFF);
+               SkGeYellowLED(pAC, io, 
+                             on ? (LED_ON >> 1) : (LED_OFF >> 1));
+               SkGeXmitLED(pAC, io, MR_ADDR(port,RX_LED_INI),
+                           on ? SK_LED_TST : SK_LED_DIS);
+
+               if (pAC->GIni.GP[port].PhyType == SK_PHY_BCOM)
+                       SkXmPhyWrite(pAC, io, port, PHY_BCOM_P_EXT_CTRL, 
+                                    on ? PHY_B_PEC_LED_ON : PHY_B_PEC_LED_OFF);
+               else if (pAC->GIni.GP[port].PhyType == SK_PHY_LONE)
+                       SkXmPhyWrite(pAC, io, port, PHY_LONE_LED_CFG,
+                                    on ? 0x0800 : PHY_L_LC_LEDT);
+               else
+                       SkGeXmitLED(pAC, io, MR_ADDR(port,TX_LED_INI),
+                                   on ? SK_LED_TST : SK_LED_DIS);
+       } else {
+               const u16 YukLedOn = (PHY_M_LED_MO_DUP(MO_LED_ON)  |
+                                     PHY_M_LED_MO_10(MO_LED_ON)   |
+                                     PHY_M_LED_MO_100(MO_LED_ON)  |
+                                     PHY_M_LED_MO_1000(MO_LED_ON) | 
+                                     PHY_M_LED_MO_RX(MO_LED_ON));
+               const u16  YukLedOff = (PHY_M_LED_MO_DUP(MO_LED_OFF)  |
+                                       PHY_M_LED_MO_10(MO_LED_OFF)   |
+                                       PHY_M_LED_MO_100(MO_LED_OFF)  |
+                                       PHY_M_LED_MO_1000(MO_LED_OFF) | 
+                                       PHY_M_LED_MO_RX(MO_LED_OFF));
+       
+
+               SkGmPhyWrite(pAC,io,port,PHY_MARV_LED_CTRL,0);
+               SkGmPhyWrite(pAC,io,port,PHY_MARV_LED_OVER, 
+                            on ? YukLedOn : YukLedOff);
+       }
+}
+
+/*****************************************************************************
+ *
+ *     skGeBlinkTimer - Changes the LED state of an adapter
+ *
+ * Description:
+ *     This function changes the current state of all LEDs of an adapter so
+ *     that it can be located by a user. If the requested time interval for
+ *     this test has elapsed, this function cleans up everything that was 
+ *     temporarily setup during the locate NIC test. This involves of course
+ *     also closing or opening any adapter so that the initial board state 
+ *     is recovered.
+ *
+ * Returns:    N/A
+ *
+ */
+void SkGeBlinkTimer(unsigned long data)
+{
+       struct net_device *dev = (struct net_device *) data;
+       DEV_NET *pNet = netdev_priv(dev);
+       SK_AC *pAC = pNet->pAC;
+
+       toggleLeds(pNet, pAC->LedsOn);
+
+       pAC->LedsOn = !pAC->LedsOn;
+       mod_timer(&pAC->BlinkTimer, jiffies + HZ/4);
+}
+
+/*****************************************************************************
+ *
+ *     locateDevice - start the locate NIC feature of the elected adapter 
+ *
+ * Description:
+ *     This function is used if the user want to locate a particular NIC.
+ *     All LEDs are regularly switched on and off, so the NIC can easily
+ *     be identified.
+ *
+ * Returns:    
+ *     ==0:    everything fine, no error, locateNIC test was started
+ *     !=0:    one locateNIC test runs already
+ *
+ */
+static int locateDevice(struct net_device *dev, u32 data)
+{
+       DEV_NET *pNet = netdev_priv(dev);
+       SK_AC *pAC = pNet->pAC;
+
+       if(!data || data > (u32)(MAX_SCHEDULE_TIMEOUT / HZ))
+               data = (u32)(MAX_SCHEDULE_TIMEOUT / HZ);
+
+       /* start blinking */
+       pAC->LedsOn = 0;
+       mod_timer(&pAC->BlinkTimer, jiffies);
+       msleep_interruptible(data * 1000);
+       del_timer_sync(&pAC->BlinkTimer);
+       toggleLeds(pNet, 0);
+
+       return 0;
+}
+
+/*****************************************************************************
+ *
+ *     getPauseParams - retrieves the pause parameters
+ *
+ * Description:
+ *     All current pause parameters of a selected adapter are placed 
+ *     in the passed ethtool_pauseparam structure and are returned.
+ *
+ * Returns:    N/A
+ *
+ */
+static void getPauseParams(struct net_device *dev, struct ethtool_pauseparam *epause) 
+{
+       DEV_NET *pNet = netdev_priv(dev);
+       SK_AC *pAC = pNet->pAC;
+       SK_GEPORT *pPort = &pAC->GIni.GP[pNet->PortNr];
+
+       epause->rx_pause = (pPort->PFlowCtrlMode == SK_FLOW_MODE_SYMMETRIC) ||
+                 (pPort->PFlowCtrlMode == SK_FLOW_MODE_SYM_OR_REM);
+
+       epause->tx_pause = epause->rx_pause || (pPort->PFlowCtrlMode == SK_FLOW_MODE_LOC_SEND);
+       epause->autoneg = epause->rx_pause || epause->tx_pause;
+}
+
+/*****************************************************************************
+ *
+ *     setPauseParams - configures the pause parameters of an adapter
+ *
+ * Description:
+ *     This function sets the Rx or Tx pause parameters 
+ *
+ * Returns:
+ *     ==0:    everything fine, no error
+ *     !=0:    the return value is the error code of the failure 
+ */
+static int setPauseParams(struct net_device *dev , struct ethtool_pauseparam *epause)
+{
+       DEV_NET *pNet = netdev_priv(dev);
+       SK_AC *pAC = pNet->pAC;
+       SK_GEPORT *pPort = &pAC->GIni.GP[pNet->PortNr];
+       u32     instance = pnmiInstance(pNet);
+       struct ethtool_pauseparam old;
+       u8      oldspeed = pPort->PLinkSpeedUsed;
+       char    buf[4];
+       int     len = 1;
+       int ret;
+
+       /*
+       ** we have to determine the current settings to see if 
+       ** the operator requested any modification of the flow 
+       ** control parameters...
+       */
+       getPauseParams(dev, &old);
+
+       /*
+       ** perform modifications regarding the changes 
+       ** requested by the operator
+       */
+       if (epause->autoneg != old.autoneg) 
+               *buf = epause->autoneg ? SK_FLOW_MODE_NONE : SK_FLOW_MODE_SYMMETRIC;
+       else {
+               if (epause->rx_pause && epause->tx_pause) 
+                       *buf = SK_FLOW_MODE_SYMMETRIC;
+               else if (epause->rx_pause && !epause->tx_pause)
+                       *buf =  SK_FLOW_MODE_SYM_OR_REM;
+               else if (!epause->rx_pause && epause->tx_pause)
+                       *buf =  SK_FLOW_MODE_LOC_SEND;
+               else
+                       *buf = SK_FLOW_MODE_NONE;
+       }
+
+       ret = SkPnmiSetVar(pAC, pAC->IoBase, OID_SKGE_FLOWCTRL_MODE,
+                        &buf, &len, instance, pNet->NetNr);
+
+       if (ret != SK_PNMI_ERR_OK) {
+               SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_CTRL,
+                          ("ethtool (sk98lin): error changing rx/tx pause (%i)\n", ret));
+               goto err;
+       }
+
+       /*
+       ** It may be that autoneg has been disabled! Therefore
+       ** set the speed to the previously used value...
+       */
+       if (!epause->autoneg) {
+               len = 1;
+               ret = SkPnmiSetVar(pAC, pAC->IoBase, OID_SKGE_SPEED_MODE, 
+                                  &oldspeed, &len, instance, pNet->NetNr);
+               if (ret != SK_PNMI_ERR_OK) 
+                       SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_CTRL,
+                                  ("ethtool (sk98lin): error setting speed (%i)\n", ret));
+       }
+ err:
+        return ret ? -EIO : 0;
+}
+
+/* Only Yukon supports checksum offload. */
+static int setScatterGather(struct net_device *dev, u32 data)
+{
+       DEV_NET *pNet = netdev_priv(dev);
+       SK_AC *pAC = pNet->pAC;
+
+       if (pAC->GIni.GIChipId == CHIP_ID_GENESIS)
+               return -EOPNOTSUPP;
+       return ethtool_op_set_sg(dev, data);
+}
+
+static int setTxCsum(struct net_device *dev, u32 data)
+{
+       DEV_NET *pNet = netdev_priv(dev);
+       SK_AC *pAC = pNet->pAC;
+
+       if (pAC->GIni.GIChipId == CHIP_ID_GENESIS)
+               return -EOPNOTSUPP;
+
+       return ethtool_op_set_tx_csum(dev, data);
+}
+
+static u32 getRxCsum(struct net_device *dev)
+{
+       DEV_NET *pNet = netdev_priv(dev);
+       SK_AC *pAC = pNet->pAC;
+
+       return pAC->RxPort[pNet->PortNr].RxCsum;
+}
+
+static int setRxCsum(struct net_device *dev, u32 data)
+{
+       DEV_NET *pNet = netdev_priv(dev);
+       SK_AC *pAC = pNet->pAC;
+
+       if (pAC->GIni.GIChipId == CHIP_ID_GENESIS)
+               return -EOPNOTSUPP;
+
+       pAC->RxPort[pNet->PortNr].RxCsum = data != 0;
+       return 0;
+}
+
+static int getRegsLen(struct net_device *dev)
+{
+       return 0x4000;
+}
+
+/*
+ * Returns copy of whole control register region
+ * Note: skip RAM address register because accessing it will
+ *      cause bus hangs!
+ */
+static void getRegs(struct net_device *dev, struct ethtool_regs *regs,
+                         void *p)
+{
+       DEV_NET *pNet = netdev_priv(dev);
+       const void __iomem *io = pNet->pAC->IoBase;
+
+       regs->version = 1;
+       memset(p, 0, regs->len);
+       memcpy_fromio(p, io, B3_RAM_ADDR);
+
+       memcpy_fromio(p + B3_RI_WTO_R1, io + B3_RI_WTO_R1,
+                     regs->len - B3_RI_WTO_R1);
+}
+
+const struct ethtool_ops SkGeEthtoolOps = {
+       .get_settings           = getSettings,
+       .set_settings           = setSettings,
+       .get_drvinfo            = getDriverInfo,
+       .get_strings            = getStrings,
+       .get_stats_count        = getStatsCount,
+       .get_ethtool_stats      = getEthtoolStats,
+       .phys_id                = locateDevice,
+       .get_pauseparam         = getPauseParams,
+       .set_pauseparam         = setPauseParams,
+       .get_link               = ethtool_op_get_link,
+       .get_sg                 = ethtool_op_get_sg,
+       .set_sg                 = setScatterGather,
+       .get_tx_csum            = ethtool_op_get_tx_csum,
+       .set_tx_csum            = setTxCsum,
+       .get_rx_csum            = getRxCsum,
+       .set_rx_csum            = setRxCsum,
+       .get_regs               = getRegs,
+       .get_regs_len           = getRegsLen,
+};
diff --git a/drivers/net/sk98lin/skge.c b/drivers/net/sk98lin/skge.c
new file mode 100644 (file)
index 0000000..7dc9c9e
--- /dev/null
@@ -0,0 +1,5219 @@
+/******************************************************************************
+ *
+ * Name:       skge.c
+ * Project:    GEnesis, PCI Gigabit Ethernet Adapter
+ * Version:    $Revision: 1.45 $
+ * Date:               $Date: 2004/02/12 14:41:02 $
+ * Purpose:    The main driver source module
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *     (C)Copyright 1998-2002 SysKonnect GmbH.
+ *     (C)Copyright 2002-2003 Marvell.
+ *
+ *     Driver for Marvell Yukon chipset and SysKonnect Gigabit Ethernet 
+ *      Server Adapters.
+ *
+ *     Created 10-Feb-1999, based on Linux' acenic.c, 3c59x.c and
+ *     SysKonnects GEnesis Solaris driver
+ *     Author: Christoph Goos (cgoos@syskonnect.de)
+ *             Mirko Lindner (mlindner@syskonnect.de)
+ *
+ *     Address all question to: linux@syskonnect.de
+ *
+ *     The technical manual for the adapters is available from SysKonnect's
+ *     web pages: www.syskonnect.com
+ *     Goto "Support" and search Knowledge Base for "manual".
+ *     
+ *     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.
+ *
+ *     The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * Possible compiler options (#define xxx / -Dxxx):
+ *
+ *     debugging can be enable by changing SK_DEBUG_CHKMOD and
+ *     SK_DEBUG_CHKCAT in makefile (described there).
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * Description:
+ *
+ *     This is the main module of the Linux GE driver.
+ *     
+ *     All source files except skge.c, skdrv1st.h, skdrv2nd.h and sktypes.h
+ *     are part of SysKonnect's COMMON MODULES for the SK-98xx adapters.
+ *     Those are used for drivers on multiple OS', so some thing may seem
+ *     unnecessary complicated on Linux. Please do not try to 'clean up'
+ *     them without VERY good reasons, because this will make it more
+ *     difficult to keep the Linux driver in synchronisation with the
+ *     other versions.
+ *
+ * Include file hierarchy:
+ *
+ *     <linux/module.h>
+ *
+ *     "h/skdrv1st.h"
+ *             <linux/types.h>
+ *             <linux/kernel.h>
+ *             <linux/string.h>
+ *             <linux/errno.h>
+ *             <linux/ioport.h>
+ *             <linux/slab.h>
+ *             <linux/interrupt.h>
+ *             <linux/pci.h>
+ *             <linux/bitops.h>
+ *             <asm/byteorder.h>
+ *             <asm/io.h>
+ *             <linux/netdevice.h>
+ *             <linux/etherdevice.h>
+ *             <linux/skbuff.h>
+ *         those three depending on kernel version used:
+ *             <linux/bios32.h>
+ *             <linux/init.h>
+ *             <asm/uaccess.h>
+ *             <net/checksum.h>
+ *
+ *             "h/skerror.h"
+ *             "h/skdebug.h"
+ *             "h/sktypes.h"
+ *             "h/lm80.h"
+ *             "h/xmac_ii.h"
+ *
+ *      "h/skdrv2nd.h"
+ *             "h/skqueue.h"
+ *             "h/skgehwt.h"
+ *             "h/sktimer.h"
+ *             "h/ski2c.h"
+ *             "h/skgepnmi.h"
+ *             "h/skvpd.h"
+ *             "h/skgehw.h"
+ *             "h/skgeinit.h"
+ *             "h/skaddr.h"
+ *             "h/skgesirq.h"
+ *             "h/skrlmt.h"
+ *
+ ******************************************************************************/
+
+#include       "h/skversion.h"
+
+#include       <linux/in.h>
+#include       <linux/module.h>
+#include       <linux/moduleparam.h>
+#include       <linux/init.h>
+#include       <linux/dma-mapping.h>
+#include       <linux/ip.h>
+#include       <linux/mii.h>
+#include       <linux/mm.h>
+
+#include       "h/skdrv1st.h"
+#include       "h/skdrv2nd.h"
+
+/*******************************************************************************
+ *
+ * Defines
+ *
+ ******************************************************************************/
+
+/* for debuging on x86 only */
+/* #define BREAKPOINT() asm(" int $3"); */
+
+/* use the transmit hw checksum driver functionality */
+#define USE_SK_TX_CHECKSUM
+
+/* use the receive hw checksum driver functionality */
+#define USE_SK_RX_CHECKSUM
+
+/* use the scatter-gather functionality with sendfile() */
+#define SK_ZEROCOPY
+
+/* use of a transmit complete interrupt */
+#define USE_TX_COMPLETE
+
+/*
+ * threshold for copying small receive frames
+ * set to 0 to avoid copying, set to 9001 to copy all frames
+ */
+#define SK_COPY_THRESHOLD      50
+
+/* number of adapters that can be configured via command line params */
+#define SK_MAX_CARD_PARAM      16
+
+
+
+/*
+ * use those defines for a compile-in version of the driver instead
+ * of command line parameters
+ */
+// #define LINK_SPEED_A        {"Auto", }
+// #define LINK_SPEED_B        {"Auto", }
+// #define AUTO_NEG_A  {"Sense", }
+// #define AUTO_NEG_B  {"Sense", }
+// #define DUP_CAP_A   {"Both", }
+// #define DUP_CAP_B   {"Both", }
+// #define FLOW_CTRL_A {"SymOrRem", }
+// #define FLOW_CTRL_B {"SymOrRem", }
+// #define ROLE_A      {"Auto", }
+// #define ROLE_B      {"Auto", }
+// #define PREF_PORT   {"A", }
+// #define CON_TYPE    {"Auto", }
+// #define RLMT_MODE   {"CheckLinkState", }
+
+#define DEV_KFREE_SKB(skb) dev_kfree_skb(skb)
+#define DEV_KFREE_SKB_IRQ(skb) dev_kfree_skb_irq(skb)
+#define DEV_KFREE_SKB_ANY(skb) dev_kfree_skb_any(skb)
+
+
+/* Set blink mode*/
+#define OEM_CONFIG_VALUE (     SK_ACT_LED_BLINK | \
+                               SK_DUP_LED_NORMAL | \
+                               SK_LED_LINK100_ON)
+
+
+/* Isr return value */
+#define SkIsrRetVar    irqreturn_t
+#define SkIsrRetNone   IRQ_NONE
+#define SkIsrRetHandled        IRQ_HANDLED
+
+
+/*******************************************************************************
+ *
+ * Local Function Prototypes
+ *
+ ******************************************************************************/
+
+static void    FreeResources(struct SK_NET_DEVICE *dev);
+static int     SkGeBoardInit(struct SK_NET_DEVICE *dev, SK_AC *pAC);
+static SK_BOOL BoardAllocMem(SK_AC *pAC);
+static void    BoardFreeMem(SK_AC *pAC);
+static void    BoardInitMem(SK_AC *pAC);
+static void    SetupRing(SK_AC*, void*, uintptr_t, RXD**, RXD**, RXD**, int*, SK_BOOL);
+static SkIsrRetVar     SkGeIsr(int irq, void *dev_id);
+static SkIsrRetVar     SkGeIsrOnePort(int irq, void *dev_id);
+static int     SkGeOpen(struct SK_NET_DEVICE *dev);
+static int     SkGeClose(struct SK_NET_DEVICE *dev);
+static int     SkGeXmit(struct sk_buff *skb, struct SK_NET_DEVICE *dev);
+static int     SkGeSetMacAddr(struct SK_NET_DEVICE *dev, void *p);
+static void    SkGeSetRxMode(struct SK_NET_DEVICE *dev);
+static struct  net_device_stats *SkGeStats(struct SK_NET_DEVICE *dev);
+static int     SkGeIoctl(struct SK_NET_DEVICE *dev, struct ifreq *rq, int cmd);
+static void    GetConfiguration(SK_AC*);
+static int     XmitFrame(SK_AC*, TX_PORT*, struct sk_buff*);
+static void    FreeTxDescriptors(SK_AC*pAC, TX_PORT*);
+static void    FillRxRing(SK_AC*, RX_PORT*);
+static SK_BOOL FillRxDescriptor(SK_AC*, RX_PORT*);
+static void    ReceiveIrq(SK_AC*, RX_PORT*, SK_BOOL);
+static void    ClearAndStartRx(SK_AC*, int);
+static void    ClearTxIrq(SK_AC*, int, int);
+static void    ClearRxRing(SK_AC*, RX_PORT*);
+static void    ClearTxRing(SK_AC*, TX_PORT*);
+static int     SkGeChangeMtu(struct SK_NET_DEVICE *dev, int new_mtu);
+static void    PortReInitBmu(SK_AC*, int);
+static int     SkGeIocMib(DEV_NET*, unsigned int, int);
+static int     SkGeInitPCI(SK_AC *pAC);
+static void    StartDrvCleanupTimer(SK_AC *pAC);
+static void    StopDrvCleanupTimer(SK_AC *pAC);
+static int     XmitFrameSG(SK_AC*, TX_PORT*, struct sk_buff*);
+
+#ifdef SK_DIAG_SUPPORT
+static SK_U32   ParseDeviceNbrFromSlotName(const char *SlotName);
+static int      SkDrvInitAdapter(SK_AC *pAC, int devNbr);
+static int      SkDrvDeInitAdapter(SK_AC *pAC, int devNbr);
+#endif
+
+/*******************************************************************************
+ *
+ * Extern Function Prototypes
+ *
+ ******************************************************************************/
+extern void SkDimEnableModerationIfNeeded(SK_AC *pAC); 
+extern void SkDimDisplayModerationSettings(SK_AC *pAC);
+extern void SkDimStartModerationTimer(SK_AC *pAC);
+extern void SkDimModerate(SK_AC *pAC);
+extern void SkGeBlinkTimer(unsigned long data);
+
+#ifdef DEBUG
+static void    DumpMsg(struct sk_buff*, char*);
+static void    DumpData(char*, int);
+static void    DumpLong(char*, int);
+#endif
+
+/* global variables *********************************************************/
+static SK_BOOL DoPrintInterfaceChange = SK_TRUE;
+extern const struct ethtool_ops SkGeEthtoolOps;
+
+/* local variables **********************************************************/
+static uintptr_t TxQueueAddr[SK_MAX_MACS][2] = {{0x680, 0x600},{0x780, 0x700}};
+static uintptr_t RxQueueAddr[SK_MAX_MACS] = {0x400, 0x480};
+
+/*****************************************************************************
+ *
+ *     SkPciWriteCfgDWord - write a 32 bit value to pci config space
+ *
+ * Description:
+ *     This routine writes a 32 bit value to the pci configuration
+ *     space.
+ *
+ * Returns:
+ *     0 - indicate everything worked ok.
+ *     != 0 - error indication
+ */
+static inline int SkPciWriteCfgDWord(
+SK_AC *pAC,    /* Adapter Control structure pointer */
+int PciAddr,           /* PCI register address */
+SK_U32 Val)            /* pointer to store the read value */
+{
+       pci_write_config_dword(pAC->PciDev, PciAddr, Val);
+       return(0);
+} /* SkPciWriteCfgDWord */
+
+/*****************************************************************************
+ *
+ *     SkGeInitPCI - Init the PCI resources
+ *
+ * Description:
+ *     This function initialize the PCI resources and IO
+ *
+ * Returns:
+ *     0 - indicate everything worked ok.
+ *     != 0 - error indication
+ */
+static __devinit int SkGeInitPCI(SK_AC *pAC)
+{
+       struct SK_NET_DEVICE *dev = pAC->dev[0];
+       struct pci_dev *pdev = pAC->PciDev;
+       int retval;
+
+       dev->mem_start = pci_resource_start (pdev, 0);
+       pci_set_master(pdev);
+
+       retval = pci_request_regions(pdev, "sk98lin");
+       if (retval)
+               goto out;
+
+#ifdef SK_BIG_ENDIAN
+       /*
+        * On big endian machines, we use the adapter's aibility of
+        * reading the descriptors as big endian.
+        */
+       {
+               SK_U32          our2;
+               SkPciReadCfgDWord(pAC, PCI_OUR_REG_2, &our2);
+               our2 |= PCI_REV_DESC;
+               SkPciWriteCfgDWord(pAC, PCI_OUR_REG_2, our2);
+       }
+#endif
+
+       /*
+        * Remap the regs into kernel space.
+        */
+       pAC->IoBase = ioremap_nocache(dev->mem_start, 0x4000);
+       if (!pAC->IoBase) {
+               retval = -EIO;
+               goto out_release;
+       }
+
+       return 0;
+
+ out_release:
+       pci_release_regions(pdev);
+ out:
+       return retval;
+}
+
+
+/*****************************************************************************
+ *
+ *     FreeResources - release resources allocated for adapter
+ *
+ * Description:
+ *     This function releases the IRQ, unmaps the IO and
+ *     frees the desriptor ring.
+ *
+ * Returns: N/A
+ *     
+ */
+static void FreeResources(struct SK_NET_DEVICE *dev)
+{
+SK_U32 AllocFlag;
+DEV_NET                *pNet;
+SK_AC          *pAC;
+
+       pNet = netdev_priv(dev);
+       pAC = pNet->pAC;
+       AllocFlag = pAC->AllocFlag;
+       if (pAC->PciDev) {
+               pci_release_regions(pAC->PciDev);
+       }
+       if (AllocFlag & SK_ALLOC_IRQ) {
+               free_irq(dev->irq, dev);
+       }
+       if (pAC->IoBase) {
+               iounmap(pAC->IoBase);
+       }
+       if (pAC->pDescrMem) {
+               BoardFreeMem(pAC);
+       }
+       
+} /* FreeResources */
+
+MODULE_AUTHOR("Mirko Lindner <mlindner@syskonnect.de>");
+MODULE_DESCRIPTION("SysKonnect SK-NET Gigabit Ethernet SK-98xx driver");
+MODULE_LICENSE("GPL");
+
+#ifdef LINK_SPEED_A
+static char *Speed_A[SK_MAX_CARD_PARAM] = LINK_SPEED;
+#else
+static char *Speed_A[SK_MAX_CARD_PARAM] = {"", };
+#endif
+
+#ifdef LINK_SPEED_B
+static char *Speed_B[SK_MAX_CARD_PARAM] = LINK_SPEED;
+#else
+static char *Speed_B[SK_MAX_CARD_PARAM] = {"", };
+#endif
+
+#ifdef AUTO_NEG_A
+static char *AutoNeg_A[SK_MAX_CARD_PARAM] = AUTO_NEG_A;
+#else
+static char *AutoNeg_A[SK_MAX_CARD_PARAM] = {"", };
+#endif
+
+#ifdef DUP_CAP_A
+static char *DupCap_A[SK_MAX_CARD_PARAM] = DUP_CAP_A;
+#else
+static char *DupCap_A[SK_MAX_CARD_PARAM] = {"", };
+#endif
+
+#ifdef FLOW_CTRL_A
+static char *FlowCtrl_A[SK_MAX_CARD_PARAM] = FLOW_CTRL_A;
+#else
+static char *FlowCtrl_A[SK_MAX_CARD_PARAM] = {"", };
+#endif
+
+#ifdef ROLE_A
+static char *Role_A[SK_MAX_CARD_PARAM] = ROLE_A;
+#else
+static char *Role_A[SK_MAX_CARD_PARAM] = {"", };
+#endif
+
+#ifdef AUTO_NEG_B
+static char *AutoNeg_B[SK_MAX_CARD_PARAM] = AUTO_NEG_B;
+#else
+static char *AutoNeg_B[SK_MAX_CARD_PARAM] = {"", };
+#endif
+
+#ifdef DUP_CAP_B
+static char *DupCap_B[SK_MAX_CARD_PARAM] = DUP_CAP_B;
+#else
+static char *DupCap_B[SK_MAX_CARD_PARAM] = {"", };
+#endif
+
+#ifdef FLOW_CTRL_B
+static char *FlowCtrl_B[SK_MAX_CARD_PARAM] = FLOW_CTRL_B;
+#else
+static char *FlowCtrl_B[SK_MAX_CARD_PARAM] = {"", };
+#endif
+
+#ifdef ROLE_B
+static char *Role_B[SK_MAX_CARD_PARAM] = ROLE_B;
+#else
+static char *Role_B[SK_MAX_CARD_PARAM] = {"", };
+#endif
+
+#ifdef CON_TYPE
+static char *ConType[SK_MAX_CARD_PARAM] = CON_TYPE;
+#else
+static char *ConType[SK_MAX_CARD_PARAM] = {"", };
+#endif
+
+#ifdef PREF_PORT
+static char *PrefPort[SK_MAX_CARD_PARAM] = PREF_PORT;
+#else
+static char *PrefPort[SK_MAX_CARD_PARAM] = {"", };
+#endif
+
+#ifdef RLMT_MODE
+static char *RlmtMode[SK_MAX_CARD_PARAM] = RLMT_MODE;
+#else
+static char *RlmtMode[SK_MAX_CARD_PARAM] = {"", };
+#endif
+
+static int   IntsPerSec[SK_MAX_CARD_PARAM];
+static char *Moderation[SK_MAX_CARD_PARAM];
+static char *ModerationMask[SK_MAX_CARD_PARAM];
+static char *AutoSizing[SK_MAX_CARD_PARAM];
+static char *Stats[SK_MAX_CARD_PARAM];
+
+module_param_array(Speed_A, charp, NULL, 0);
+module_param_array(Speed_B, charp, NULL, 0);
+module_param_array(AutoNeg_A, charp, NULL, 0);
+module_param_array(AutoNeg_B, charp, NULL, 0);
+module_param_array(DupCap_A, charp, NULL, 0);
+module_param_array(DupCap_B, charp, NULL, 0);
+module_param_array(FlowCtrl_A, charp, NULL, 0);
+module_param_array(FlowCtrl_B, charp, NULL, 0);
+module_param_array(Role_A, charp, NULL, 0);
+module_param_array(Role_B, charp, NULL, 0);
+module_param_array(ConType, charp, NULL, 0);
+module_param_array(PrefPort, charp, NULL, 0);
+module_param_array(RlmtMode, charp, NULL, 0);
+/* used for interrupt moderation */
+module_param_array(IntsPerSec, int, NULL, 0);
+module_param_array(Moderation, charp, NULL, 0);
+module_param_array(Stats, charp, NULL, 0);
+module_param_array(ModerationMask, charp, NULL, 0);
+module_param_array(AutoSizing, charp, NULL, 0);
+
+/*****************************************************************************
+ *
+ *     SkGeBoardInit - do level 0 and 1 initialization
+ *
+ * Description:
+ *     This function prepares the board hardware for running. The desriptor
+ *     ring is set up, the IRQ is allocated and the configuration settings
+ *     are examined.
+ *
+ * Returns:
+ *     0, if everything is ok
+ *     !=0, on error
+ */
+static int __devinit SkGeBoardInit(struct SK_NET_DEVICE *dev, SK_AC *pAC)
+{
+short  i;
+unsigned long Flags;
+char   *DescrString = "sk98lin: Driver for Linux"; /* this is given to PNMI */
+char   *VerStr = VER_STRING;
+int    Ret;                    /* return code of request_irq */
+SK_BOOL        DualNet;
+
+       SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY,
+               ("IoBase: %08lX\n", (unsigned long)pAC->IoBase));
+       for (i=0; i<SK_MAX_MACS; i++) {
+               pAC->TxPort[i][0].HwAddr = pAC->IoBase + TxQueueAddr[i][0];
+               pAC->TxPort[i][0].PortIndex = i;
+               pAC->RxPort[i].HwAddr = pAC->IoBase + RxQueueAddr[i];
+               pAC->RxPort[i].PortIndex = i;
+       }
+
+       /* Initialize the mutexes */
+       for (i=0; i<SK_MAX_MACS; i++) {
+               spin_lock_init(&pAC->TxPort[i][0].TxDesRingLock);
+               spin_lock_init(&pAC->RxPort[i].RxDesRingLock);
+       }
+       spin_lock_init(&pAC->SlowPathLock);
+
+       /* setup phy_id blink timer */
+       pAC->BlinkTimer.function = SkGeBlinkTimer;
+       pAC->BlinkTimer.data = (unsigned long) dev;
+       init_timer(&pAC->BlinkTimer);
+
+       /* level 0 init common modules here */
+       
+       spin_lock_irqsave(&pAC->SlowPathLock, Flags);
+       /* Does a RESET on board ...*/
+       if (SkGeInit(pAC, pAC->IoBase, SK_INIT_DATA) != 0) {
+               printk("HWInit (0) failed.\n");
+               spin_unlock_irqrestore(&pAC->SlowPathLock, Flags);
+               return -EIO;
+       }
+       SkI2cInit(  pAC, pAC->IoBase, SK_INIT_DATA);
+       SkEventInit(pAC, pAC->IoBase, SK_INIT_DATA);
+       SkPnmiInit( pAC, pAC->IoBase, SK_INIT_DATA);
+       SkAddrInit( pAC, pAC->IoBase, SK_INIT_DATA);
+       SkRlmtInit( pAC, pAC->IoBase, SK_INIT_DATA);
+       SkTimerInit(pAC, pAC->IoBase, SK_INIT_DATA);
+
+       pAC->BoardLevel = SK_INIT_DATA;
+       pAC->RxBufSize  = ETH_BUF_SIZE;
+
+       SK_PNMI_SET_DRIVER_DESCR(pAC, DescrString);
+       SK_PNMI_SET_DRIVER_VER(pAC, VerStr);
+
+       spin_unlock_irqrestore(&pAC->SlowPathLock, Flags);
+
+       /* level 1 init common modules here (HW init) */
+       spin_lock_irqsave(&pAC->SlowPathLock, Flags);
+       if (SkGeInit(pAC, pAC->IoBase, SK_INIT_IO) != 0) {
+               printk("sk98lin: HWInit (1) failed.\n");
+               spin_unlock_irqrestore(&pAC->SlowPathLock, Flags);
+               return -EIO;
+       }
+       SkI2cInit(  pAC, pAC->IoBase, SK_INIT_IO);
+       SkEventInit(pAC, pAC->IoBase, SK_INIT_IO);
+       SkPnmiInit( pAC, pAC->IoBase, SK_INIT_IO);
+       SkAddrInit( pAC, pAC->IoBase, SK_INIT_IO);
+       SkRlmtInit( pAC, pAC->IoBase, SK_INIT_IO);
+       SkTimerInit(pAC, pAC->IoBase, SK_INIT_IO);
+
+       /* Set chipset type support */
+       pAC->ChipsetType = 0;
+       if ((pAC->GIni.GIChipId == CHIP_ID_YUKON) ||
+               (pAC->GIni.GIChipId == CHIP_ID_YUKON_LITE)) {
+               pAC->ChipsetType = 1;
+       }
+
+       GetConfiguration(pAC);
+       if (pAC->RlmtNets == 2) {
+               pAC->GIni.GIPortUsage = SK_MUL_LINK;
+       }
+
+       pAC->BoardLevel = SK_INIT_IO;
+       spin_unlock_irqrestore(&pAC->SlowPathLock, Flags);
+
+       if (pAC->GIni.GIMacsFound == 2) {
+                Ret = request_irq(dev->irq, SkGeIsr, IRQF_SHARED, "sk98lin", dev);
+       } else if (pAC->GIni.GIMacsFound == 1) {
+               Ret = request_irq(dev->irq, SkGeIsrOnePort, IRQF_SHARED,
+                       "sk98lin", dev);
+       } else {
+               printk(KERN_WARNING "sk98lin: Illegal number of ports: %d\n",
+                      pAC->GIni.GIMacsFound);
+               return -EIO;
+       }
+
+       if (Ret) {
+               printk(KERN_WARNING "sk98lin: Requested IRQ %d is busy.\n",
+                      dev->irq);
+               return Ret;
+       }
+       pAC->AllocFlag |= SK_ALLOC_IRQ;
+
+       /* Alloc memory for this board (Mem for RxD/TxD) : */
+       if(!BoardAllocMem(pAC)) {
+               printk("No memory for descriptor rings.\n");
+               return -ENOMEM;
+       }
+
+       BoardInitMem(pAC);
+       /* tschilling: New common function with minimum size check. */
+       DualNet = SK_FALSE;
+       if (pAC->RlmtNets == 2) {
+               DualNet = SK_TRUE;
+       }
+       
+       if (SkGeInitAssignRamToQueues(
+               pAC,
+               pAC->ActivePort,
+               DualNet)) {
+               BoardFreeMem(pAC);
+               printk("sk98lin: SkGeInitAssignRamToQueues failed.\n");
+               return -EIO;
+       }
+
+       return (0);
+} /* SkGeBoardInit */
+
+
+/*****************************************************************************
+ *
+ *     BoardAllocMem - allocate the memory for the descriptor rings
+ *
+ * Description:
+ *     This function allocates the memory for all descriptor rings.
+ *     Each ring is aligned for the desriptor alignment and no ring
+ *     has a 4 GByte boundary in it (because the upper 32 bit must
+ *     be constant for all descriptiors in one rings).
+ *
+ * Returns:
+ *     SK_TRUE, if all memory could be allocated
+ *     SK_FALSE, if not
+ */
+static __devinit SK_BOOL BoardAllocMem(SK_AC   *pAC)
+{
+caddr_t                pDescrMem;      /* pointer to descriptor memory area */
+size_t         AllocLength;    /* length of complete descriptor area */
+int            i;              /* loop counter */
+unsigned long  BusAddr;
+
+       
+       /* rings plus one for alignment (do not cross 4 GB boundary) */
+       /* RX_RING_SIZE is assumed bigger than TX_RING_SIZE */
+#if (BITS_PER_LONG == 32)
+       AllocLength = (RX_RING_SIZE + TX_RING_SIZE) * pAC->GIni.GIMacsFound + 8;
+#else
+       AllocLength = (RX_RING_SIZE + TX_RING_SIZE) * pAC->GIni.GIMacsFound
+               + RX_RING_SIZE + 8;
+#endif
+
+       pDescrMem = pci_alloc_consistent(pAC->PciDev, AllocLength,
+                                        &pAC->pDescrMemDMA);
+
+       if (pDescrMem == NULL) {
+               return (SK_FALSE);
+       }
+       pAC->pDescrMem = pDescrMem;
+       BusAddr = (unsigned long) pAC->pDescrMemDMA;
+
+       /* Descriptors need 8 byte alignment, and this is ensured
+        * by pci_alloc_consistent.
+        */
+       for (i=0; i<pAC->GIni.GIMacsFound; i++) {
+               SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_TX_PROGRESS,
+                       ("TX%d/A: pDescrMem: %lX,   PhysDescrMem: %lX\n",
+                       i, (unsigned long) pDescrMem,
+                       BusAddr));
+               pAC->TxPort[i][0].pTxDescrRing = pDescrMem;
+               pAC->TxPort[i][0].VTxDescrRing = BusAddr;
+               pDescrMem += TX_RING_SIZE;
+               BusAddr += TX_RING_SIZE;
+       
+               SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_TX_PROGRESS,
+                       ("RX%d: pDescrMem: %lX,   PhysDescrMem: %lX\n",
+                       i, (unsigned long) pDescrMem,
+                       (unsigned long)BusAddr));
+               pAC->RxPort[i].pRxDescrRing = pDescrMem;
+               pAC->RxPort[i].VRxDescrRing = BusAddr;
+               pDescrMem += RX_RING_SIZE;
+               BusAddr += RX_RING_SIZE;
+       } /* for */
+       
+       return (SK_TRUE);
+} /* BoardAllocMem */
+
+
+/****************************************************************************
+ *
+ *     BoardFreeMem - reverse of BoardAllocMem
+ *
+ * Description:
+ *     Free all memory allocated in BoardAllocMem: adapter context,
+ *     descriptor rings, locks.
+ *
+ * Returns:    N/A
+ */
+static void BoardFreeMem(
+SK_AC          *pAC)
+{
+size_t         AllocLength;    /* length of complete descriptor area */
+
+       SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY,
+               ("BoardFreeMem\n"));
+#if (BITS_PER_LONG == 32)
+       AllocLength = (RX_RING_SIZE + TX_RING_SIZE) * pAC->GIni.GIMacsFound + 8;
+#else
+       AllocLength = (RX_RING_SIZE + TX_RING_SIZE) * pAC->GIni.GIMacsFound
+               + RX_RING_SIZE + 8;
+#endif
+
+       pci_free_consistent(pAC->PciDev, AllocLength,
+                           pAC->pDescrMem, pAC->pDescrMemDMA);
+       pAC->pDescrMem = NULL;
+} /* BoardFreeMem */
+
+
+/*****************************************************************************
+ *
+ *     BoardInitMem - initiate the descriptor rings
+ *
+ * Description:
+ *     This function sets the descriptor rings up in memory.
+ *     The adapter is initialized with the descriptor start addresses.
+ *
+ * Returns:    N/A
+ */
+static __devinit void BoardInitMem(SK_AC *pAC)
+{
+int    i;              /* loop counter */
+int    RxDescrSize;    /* the size of a rx descriptor rounded up to alignment*/
+int    TxDescrSize;    /* the size of a tx descriptor rounded up to alignment*/
+
+       SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY,
+               ("BoardInitMem\n"));
+
+       RxDescrSize = (((sizeof(RXD) - 1) / DESCR_ALIGN) + 1) * DESCR_ALIGN;
+       pAC->RxDescrPerRing = RX_RING_SIZE / RxDescrSize;
+       TxDescrSize = (((sizeof(TXD) - 1) / DESCR_ALIGN) + 1) * DESCR_ALIGN;
+       pAC->TxDescrPerRing = TX_RING_SIZE / RxDescrSize;
+       
+       for (i=0; i<pAC->GIni.GIMacsFound; i++) {
+               SetupRing(
+                       pAC,
+                       pAC->TxPort[i][0].pTxDescrRing,
+                       pAC->TxPort[i][0].VTxDescrRing,
+                       (RXD**)&pAC->TxPort[i][0].pTxdRingHead,
+                       (RXD**)&pAC->TxPort[i][0].pTxdRingTail,
+                       (RXD**)&pAC->TxPort[i][0].pTxdRingPrev,
+                       &pAC->TxPort[i][0].TxdRingFree,
+                       SK_TRUE);
+               SetupRing(
+                       pAC,
+                       pAC->RxPort[i].pRxDescrRing,
+                       pAC->RxPort[i].VRxDescrRing,
+                       &pAC->RxPort[i].pRxdRingHead,
+                       &pAC->RxPort[i].pRxdRingTail,
+                       &pAC->RxPort[i].pRxdRingPrev,
+                       &pAC->RxPort[i].RxdRingFree,
+                       SK_FALSE);
+       }
+} /* BoardInitMem */
+
+
+/*****************************************************************************
+ *
+ *     SetupRing - create one descriptor ring
+ *
+ * Description:
+ *     This function creates one descriptor ring in the given memory area.
+ *     The head, tail and number of free descriptors in the ring are set.
+ *
+ * Returns:
+ *     none
+ */
+static void SetupRing(
+SK_AC          *pAC,
+void           *pMemArea,      /* a pointer to the memory area for the ring */
+uintptr_t      VMemArea,       /* the virtual bus address of the memory area */
+RXD            **ppRingHead,   /* address where the head should be written */
+RXD            **ppRingTail,   /* address where the tail should be written */
+RXD            **ppRingPrev,   /* address where the tail should be written */
+int            *pRingFree,     /* address where the # of free descr. goes */
+SK_BOOL                IsTx)           /* flag: is this a tx ring */
+{
+int    i;              /* loop counter */
+int    DescrSize;      /* the size of a descriptor rounded up to alignment*/
+int    DescrNum;       /* number of descriptors per ring */
+RXD    *pDescr;        /* pointer to a descriptor (receive or transmit) */
+RXD    *pNextDescr;    /* pointer to the next descriptor */
+RXD    *pPrevDescr;    /* pointer to the previous descriptor */
+uintptr_t VNextDescr;  /* the virtual bus address of the next descriptor */
+
+       if (IsTx == SK_TRUE) {
+               DescrSize = (((sizeof(TXD) - 1) / DESCR_ALIGN) + 1) *
+                       DESCR_ALIGN;
+               DescrNum = TX_RING_SIZE / DescrSize;
+       } else {
+               DescrSize = (((sizeof(RXD) - 1) / DESCR_ALIGN) + 1) *
+                       DESCR_ALIGN;
+               DescrNum = RX_RING_SIZE / DescrSize;
+       }
+       
+       SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_TX_PROGRESS,
+               ("Descriptor size: %d   Descriptor Number: %d\n",
+               DescrSize,DescrNum));
+       
+       pDescr = (RXD*) pMemArea;
+       pPrevDescr = NULL;
+       pNextDescr = (RXD*) (((char*)pDescr) + DescrSize);
+       VNextDescr = VMemArea + DescrSize;
+       for(i=0; i<DescrNum; i++) {
+               /* set the pointers right */
+               pDescr->VNextRxd = VNextDescr & 0xffffffffULL;
+               pDescr->pNextRxd = pNextDescr;
+               if (!IsTx) pDescr->TcpSumStarts = ETH_HLEN << 16 | ETH_HLEN;
+
+               /* advance one step */
+               pPrevDescr = pDescr;
+               pDescr = pNextDescr;
+               pNextDescr = (RXD*) (((char*)pDescr) + DescrSize);
+               VNextDescr += DescrSize;
+       }
+       pPrevDescr->pNextRxd = (RXD*) pMemArea;
+       pPrevDescr->VNextRxd = VMemArea;
+       pDescr = (RXD*) pMemArea;
+       *ppRingHead = (RXD*) pMemArea;
+       *ppRingTail = *ppRingHead;
+       *ppRingPrev = pPrevDescr;
+       *pRingFree = DescrNum;
+} /* SetupRing */
+
+
+/*****************************************************************************
+ *
+ *     PortReInitBmu - re-initiate the descriptor rings for one port
+ *
+ * Description:
+ *     This function reinitializes the descriptor rings of one port
+ *     in memory. The port must be stopped before.
+ *     The HW is initialized with the descriptor start addresses.
+ *
+ * Returns:
+ *     none
+ */
+static void PortReInitBmu(
+SK_AC  *pAC,           /* pointer to adapter context */
+int    PortIndex)      /* index of the port for which to re-init */
+{
+       SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY,
+               ("PortReInitBmu "));
+
+       /* set address of first descriptor of ring in BMU */
+       SK_OUT32(pAC->IoBase, TxQueueAddr[PortIndex][TX_PRIO_LOW]+ Q_DA_L,
+               (uint32_t)(((caddr_t)
+               (pAC->TxPort[PortIndex][TX_PRIO_LOW].pTxdRingHead) -
+               pAC->TxPort[PortIndex][TX_PRIO_LOW].pTxDescrRing +
+               pAC->TxPort[PortIndex][TX_PRIO_LOW].VTxDescrRing) &
+               0xFFFFFFFF));
+       SK_OUT32(pAC->IoBase, TxQueueAddr[PortIndex][TX_PRIO_LOW]+ Q_DA_H,
+               (uint32_t)(((caddr_t)
+               (pAC->TxPort[PortIndex][TX_PRIO_LOW].pTxdRingHead) -
+               pAC->TxPort[PortIndex][TX_PRIO_LOW].pTxDescrRing +
+               pAC->TxPort[PortIndex][TX_PRIO_LOW].VTxDescrRing) >> 32));
+       SK_OUT32(pAC->IoBase, RxQueueAddr[PortIndex]+Q_DA_L,
+               (uint32_t)(((caddr_t)(pAC->RxPort[PortIndex].pRxdRingHead) -
+               pAC->RxPort[PortIndex].pRxDescrRing +
+               pAC->RxPort[PortIndex].VRxDescrRing) & 0xFFFFFFFF));
+       SK_OUT32(pAC->IoBase, RxQueueAddr[PortIndex]+Q_DA_H,
+               (uint32_t)(((caddr_t)(pAC->RxPort[PortIndex].pRxdRingHead) -
+               pAC->RxPort[PortIndex].pRxDescrRing +
+               pAC->RxPort[PortIndex].VRxDescrRing) >> 32));
+} /* PortReInitBmu */
+
+
+/****************************************************************************
+ *
+ *     SkGeIsr - handle adapter interrupts
+ *
+ * Description:
+ *     The interrupt routine is called when the network adapter
+ *     generates an interrupt. It may also be called if another device
+ *     shares this interrupt vector with the driver.
+ *
+ * Returns: N/A
+ *
+ */
+static SkIsrRetVar SkGeIsr(int irq, void *dev_id)
+{
+struct SK_NET_DEVICE *dev = (struct SK_NET_DEVICE *)dev_id;
+DEV_NET                *pNet;
+SK_AC          *pAC;
+SK_U32         IntSrc;         /* interrupts source register contents */       
+
+       pNet = netdev_priv(dev);
+       pAC = pNet->pAC;
+       
+       /*
+        * Check and process if its our interrupt
+        */
+       SK_IN32(pAC->IoBase, B0_SP_ISRC, &IntSrc);
+       if (IntSrc == 0) {
+               return SkIsrRetNone;
+       }
+
+       while (((IntSrc & IRQ_MASK) & ~SPECIAL_IRQS) != 0) {
+#if 0 /* software irq currently not used */
+               if (IntSrc & IS_IRQ_SW) {
+                       SK_DBG_MSG(NULL, SK_DBGMOD_DRV,
+                               SK_DBGCAT_DRV_INT_SRC,
+                               ("Software IRQ\n"));
+               }
+#endif
+               if (IntSrc & IS_R1_F) {
+                       SK_DBG_MSG(NULL, SK_DBGMOD_DRV,
+                               SK_DBGCAT_DRV_INT_SRC,
+                               ("EOF RX1 IRQ\n"));
+                       ReceiveIrq(pAC, &pAC->RxPort[0], SK_TRUE);
+                       SK_PNMI_CNT_RX_INTR(pAC, 0);
+               }
+               if (IntSrc & IS_R2_F) {
+                       SK_DBG_MSG(NULL, SK_DBGMOD_DRV,
+                               SK_DBGCAT_DRV_INT_SRC,
+                               ("EOF RX2 IRQ\n"));
+                       ReceiveIrq(pAC, &pAC->RxPort[1], SK_TRUE);
+                       SK_PNMI_CNT_RX_INTR(pAC, 1);
+               }
+#ifdef USE_TX_COMPLETE /* only if tx complete interrupt used */
+               if (IntSrc & IS_XA1_F) {
+                       SK_DBG_MSG(NULL, SK_DBGMOD_DRV,
+                               SK_DBGCAT_DRV_INT_SRC,
+                               ("EOF AS TX1 IRQ\n"));
+                       SK_PNMI_CNT_TX_INTR(pAC, 0);
+                       spin_lock(&pAC->TxPort[0][TX_PRIO_LOW].TxDesRingLock);
+                       FreeTxDescriptors(pAC, &pAC->TxPort[0][TX_PRIO_LOW]);
+                       spin_unlock(&pAC->TxPort[0][TX_PRIO_LOW].TxDesRingLock);
+               }
+               if (IntSrc & IS_XA2_F) {
+                       SK_DBG_MSG(NULL, SK_DBGMOD_DRV,
+                               SK_DBGCAT_DRV_INT_SRC,
+                               ("EOF AS TX2 IRQ\n"));
+                       SK_PNMI_CNT_TX_INTR(pAC, 1);
+                       spin_lock(&pAC->TxPort[1][TX_PRIO_LOW].TxDesRingLock);
+                       FreeTxDescriptors(pAC, &pAC->TxPort[1][TX_PRIO_LOW]);
+                       spin_unlock(&pAC->TxPort[1][TX_PRIO_LOW].TxDesRingLock);
+               }
+#if 0 /* only if sync. queues used */
+               if (IntSrc & IS_XS1_F) {
+                       SK_DBG_MSG(NULL, SK_DBGMOD_DRV,
+                               SK_DBGCAT_DRV_INT_SRC,
+                               ("EOF SY TX1 IRQ\n"));
+                       SK_PNMI_CNT_TX_INTR(pAC, 1);
+                       spin_lock(&pAC->TxPort[0][TX_PRIO_HIGH].TxDesRingLock);
+                       FreeTxDescriptors(pAC, 0, TX_PRIO_HIGH);
+                       spin_unlock(&pAC->TxPort[0][TX_PRIO_HIGH].TxDesRingLock);
+                       ClearTxIrq(pAC, 0, TX_PRIO_HIGH);
+               }
+               if (IntSrc & IS_XS2_F) {
+                       SK_DBG_MSG(NULL, SK_DBGMOD_DRV,
+                               SK_DBGCAT_DRV_INT_SRC,
+                               ("EOF SY TX2 IRQ\n"));
+                       SK_PNMI_CNT_TX_INTR(pAC, 1);
+                       spin_lock(&pAC->TxPort[1][TX_PRIO_HIGH].TxDesRingLock);
+                       FreeTxDescriptors(pAC, 1, TX_PRIO_HIGH);
+                       spin_unlock(&pAC->TxPort[1][TX_PRIO_HIGH].TxDesRingLock);
+                       ClearTxIrq(pAC, 1, TX_PRIO_HIGH);
+               }
+#endif
+#endif
+
+               /* do all IO at once */
+               if (IntSrc & IS_R1_F)
+                       ClearAndStartRx(pAC, 0);
+               if (IntSrc & IS_R2_F)
+                       ClearAndStartRx(pAC, 1);
+#ifdef USE_TX_COMPLETE /* only if tx complete interrupt used */
+               if (IntSrc & IS_XA1_F)
+                       ClearTxIrq(pAC, 0, TX_PRIO_LOW);
+               if (IntSrc & IS_XA2_F)
+                       ClearTxIrq(pAC, 1, TX_PRIO_LOW);
+#endif
+               SK_IN32(pAC->IoBase, B0_ISRC, &IntSrc);
+       } /* while (IntSrc & IRQ_MASK != 0) */
+
+       IntSrc &= pAC->GIni.GIValIrqMask;
+       if ((IntSrc & SPECIAL_IRQS) || pAC->CheckQueue) {
+               SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_INT_SRC,
+                       ("SPECIAL IRQ DP-Cards => %x\n", IntSrc));
+               pAC->CheckQueue = SK_FALSE;
+               spin_lock(&pAC->SlowPathLock);
+               if (IntSrc & SPECIAL_IRQS)
+                       SkGeSirqIsr(pAC, pAC->IoBase, IntSrc);
+
+               SkEventDispatcher(pAC, pAC->IoBase);
+               spin_unlock(&pAC->SlowPathLock);
+       }
+       /*
+        * do it all again is case we cleared an interrupt that
+        * came in after handling the ring (OUTs may be delayed
+        * in hardware buffers, but are through after IN)
+        *
+        * rroesler: has been commented out and shifted to
+        *           SkGeDrvEvent(), because it is timer
+        *           guarded now
+        *
+       ReceiveIrq(pAC, &pAC->RxPort[0], SK_TRUE);
+       ReceiveIrq(pAC, &pAC->RxPort[1], SK_TRUE);
+        */
+
+       if (pAC->CheckQueue) {
+               pAC->CheckQueue = SK_FALSE;
+               spin_lock(&pAC->SlowPathLock);
+               SkEventDispatcher(pAC, pAC->IoBase);
+               spin_unlock(&pAC->SlowPathLock);
+       }
+
+       /* IRQ is processed - Enable IRQs again*/
+       SK_OUT32(pAC->IoBase, B0_IMSK, pAC->GIni.GIValIrqMask);
+
+               return SkIsrRetHandled;
+} /* SkGeIsr */
+
+
+/****************************************************************************
+ *
+ *     SkGeIsrOnePort - handle adapter interrupts for single port adapter
+ *
+ * Description:
+ *     The interrupt routine is called when the network adapter
+ *     generates an interrupt. It may also be called if another device
+ *     shares this interrupt vector with the driver.
+ *     This is the same as above, but handles only one port.
+ *
+ * Returns: N/A
+ *
+ */
+static SkIsrRetVar SkGeIsrOnePort(int irq, void *dev_id)
+{
+struct SK_NET_DEVICE *dev = (struct SK_NET_DEVICE *)dev_id;
+DEV_NET                *pNet;
+SK_AC          *pAC;
+SK_U32         IntSrc;         /* interrupts source register contents */       
+
+       pNet = netdev_priv(dev);
+       pAC = pNet->pAC;
+       
+       /*
+        * Check and process if its our interrupt
+        */
+       SK_IN32(pAC->IoBase, B0_SP_ISRC, &IntSrc);
+       if (IntSrc == 0) {
+               return SkIsrRetNone;
+       }
+       
+       while (((IntSrc & IRQ_MASK) & ~SPECIAL_IRQS) != 0) {
+#if 0 /* software irq currently not used */
+               if (IntSrc & IS_IRQ_SW) {
+                       SK_DBG_MSG(NULL, SK_DBGMOD_DRV,
+                               SK_DBGCAT_DRV_INT_SRC,
+                               ("Software IRQ\n"));
+               }
+#endif
+               if (IntSrc & IS_R1_F) {
+                       SK_DBG_MSG(NULL, SK_DBGMOD_DRV,
+                               SK_DBGCAT_DRV_INT_SRC,
+                               ("EOF RX1 IRQ\n"));
+                       ReceiveIrq(pAC, &pAC->RxPort[0], SK_TRUE);
+                       SK_PNMI_CNT_RX_INTR(pAC, 0);
+               }
+#ifdef USE_TX_COMPLETE /* only if tx complete interrupt used */
+               if (IntSrc & IS_XA1_F) {
+                       SK_DBG_MSG(NULL, SK_DBGMOD_DRV,
+                               SK_DBGCAT_DRV_INT_SRC,
+                               ("EOF AS TX1 IRQ\n"));
+                       SK_PNMI_CNT_TX_INTR(pAC, 0);
+                       spin_lock(&pAC->TxPort[0][TX_PRIO_LOW].TxDesRingLock);
+                       FreeTxDescriptors(pAC, &pAC->TxPort[0][TX_PRIO_LOW]);
+                       spin_unlock(&pAC->TxPort[0][TX_PRIO_LOW].TxDesRingLock);
+               }
+#if 0 /* only if sync. queues used */
+               if (IntSrc & IS_XS1_F) {
+                       SK_DBG_MSG(NULL, SK_DBGMOD_DRV,
+                               SK_DBGCAT_DRV_INT_SRC,
+                               ("EOF SY TX1 IRQ\n"));
+                       SK_PNMI_CNT_TX_INTR(pAC, 0);
+                       spin_lock(&pAC->TxPort[0][TX_PRIO_HIGH].TxDesRingLock);
+                       FreeTxDescriptors(pAC, 0, TX_PRIO_HIGH);
+                       spin_unlock(&pAC->TxPort[0][TX_PRIO_HIGH].TxDesRingLock);
+                       ClearTxIrq(pAC, 0, TX_PRIO_HIGH);
+               }
+#endif
+#endif
+
+               /* do all IO at once */
+               if (IntSrc & IS_R1_F)
+                       ClearAndStartRx(pAC, 0);
+#ifdef USE_TX_COMPLETE /* only if tx complete interrupt used */
+               if (IntSrc & IS_XA1_F)
+                       ClearTxIrq(pAC, 0, TX_PRIO_LOW);
+#endif
+               SK_IN32(pAC->IoBase, B0_ISRC, &IntSrc);
+       } /* while (IntSrc & IRQ_MASK != 0) */
+       
+       IntSrc &= pAC->GIni.GIValIrqMask;
+       if ((IntSrc & SPECIAL_IRQS) || pAC->CheckQueue) {
+               SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_INT_SRC,
+                       ("SPECIAL IRQ SP-Cards => %x\n", IntSrc));
+               pAC->CheckQueue = SK_FALSE;
+               spin_lock(&pAC->SlowPathLock);
+               if (IntSrc & SPECIAL_IRQS)
+                       SkGeSirqIsr(pAC, pAC->IoBase, IntSrc);
+
+               SkEventDispatcher(pAC, pAC->IoBase);
+               spin_unlock(&pAC->SlowPathLock);
+       }
+       /*
+        * do it all again is case we cleared an interrupt that
+        * came in after handling the ring (OUTs may be delayed
+        * in hardware buffers, but are through after IN)
+        *
+        * rroesler: has been commented out and shifted to
+        *           SkGeDrvEvent(), because it is timer
+        *           guarded now
+        *
+       ReceiveIrq(pAC, &pAC->RxPort[0], SK_TRUE);
+        */
+
+       /* IRQ is processed - Enable IRQs again*/
+       SK_OUT32(pAC->IoBase, B0_IMSK, pAC->GIni.GIValIrqMask);
+
+               return SkIsrRetHandled;
+} /* SkGeIsrOnePort */
+
+#ifdef CONFIG_NET_POLL_CONTROLLER
+/****************************************************************************
+ *
+ *     SkGePollController - polling receive, for netconsole
+ *
+ * Description:
+ *     Polling receive - used by netconsole and other diagnostic tools
+ *     to allow network i/o with interrupts disabled.
+ *
+ * Returns: N/A
+ */
+static void SkGePollController(struct net_device *dev)
+{
+       disable_irq(dev->irq);
+       SkGeIsr(dev->irq, dev);
+       enable_irq(dev->irq);
+}
+#endif
+
+/****************************************************************************
+ *
+ *     SkGeOpen - handle start of initialized adapter
+ *
+ * Description:
+ *     This function starts the initialized adapter.
+ *     The board level variable is set and the adapter is
+ *     brought to full functionality.
+ *     The device flags are set for operation.
+ *     Do all necessary level 2 initialization, enable interrupts and
+ *     give start command to RLMT.
+ *
+ * Returns:
+ *     0 on success
+ *     != 0 on error
+ */
+static int SkGeOpen(
+struct SK_NET_DEVICE   *dev)
+{
+       DEV_NET                 *pNet;
+       SK_AC                   *pAC;
+       unsigned long   Flags;          /* for spin lock */
+       int                             i;
+       SK_EVPARA               EvPara;         /* an event parameter union */
+
+       pNet = netdev_priv(dev);
+       pAC = pNet->pAC;
+       
+       SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY,
+               ("SkGeOpen: pAC=0x%lX:\n", (unsigned long)pAC));
+
+#ifdef SK_DIAG_SUPPORT
+       if (pAC->DiagModeActive == DIAG_ACTIVE) {
+               if (pAC->Pnmi.DiagAttached == SK_DIAG_RUNNING) {
+                       return (-1);   /* still in use by diag; deny actions */
+               } 
+       }
+#endif
+
+       /* Set blink mode */
+       if ((pAC->PciDev->vendor == 0x1186) || (pAC->PciDev->vendor == 0x11ab ))
+               pAC->GIni.GILedBlinkCtrl = OEM_CONFIG_VALUE;
+
+       if (pAC->BoardLevel == SK_INIT_DATA) {
+               /* level 1 init common modules here */
+               if (SkGeInit(pAC, pAC->IoBase, SK_INIT_IO) != 0) {
+                       printk("%s: HWInit (1) failed.\n", pAC->dev[pNet->PortNr]->name);
+                       return (-1);
+               }
+               SkI2cInit       (pAC, pAC->IoBase, SK_INIT_IO);
+               SkEventInit     (pAC, pAC->IoBase, SK_INIT_IO);
+               SkPnmiInit      (pAC, pAC->IoBase, SK_INIT_IO);
+               SkAddrInit      (pAC, pAC->IoBase, SK_INIT_IO);
+               SkRlmtInit      (pAC, pAC->IoBase, SK_INIT_IO);
+               SkTimerInit     (pAC, pAC->IoBase, SK_INIT_IO);
+               pAC->BoardLevel = SK_INIT_IO;
+       }
+
+       if (pAC->BoardLevel != SK_INIT_RUN) {
+               /* tschilling: Level 2 init modules here, check return value. */
+               if (SkGeInit(pAC, pAC->IoBase, SK_INIT_RUN) != 0) {
+                       printk("%s: HWInit (2) failed.\n", pAC->dev[pNet->PortNr]->name);
+                       return (-1);
+               }
+               SkI2cInit       (pAC, pAC->IoBase, SK_INIT_RUN);
+               SkEventInit     (pAC, pAC->IoBase, SK_INIT_RUN);
+               SkPnmiInit      (pAC, pAC->IoBase, SK_INIT_RUN);
+               SkAddrInit      (pAC, pAC->IoBase, SK_INIT_RUN);
+               SkRlmtInit      (pAC, pAC->IoBase, SK_INIT_RUN);
+               SkTimerInit     (pAC, pAC->IoBase, SK_INIT_RUN);
+               pAC->BoardLevel = SK_INIT_RUN;
+       }
+
+       for (i=0; i<pAC->GIni.GIMacsFound; i++) {
+               /* Enable transmit descriptor polling. */
+               SkGePollTxD(pAC, pAC->IoBase, i, SK_TRUE);
+               FillRxRing(pAC, &pAC->RxPort[i]);
+       }
+       SkGeYellowLED(pAC, pAC->IoBase, 1);
+
+       StartDrvCleanupTimer(pAC);
+       SkDimEnableModerationIfNeeded(pAC);     
+       SkDimDisplayModerationSettings(pAC);
+
+       pAC->GIni.GIValIrqMask &= IRQ_MASK;
+
+       /* enable Interrupts */
+       SK_OUT32(pAC->IoBase, B0_IMSK, pAC->GIni.GIValIrqMask);
+       SK_OUT32(pAC->IoBase, B0_HWE_IMSK, IRQ_HWE_MASK);
+
+       spin_lock_irqsave(&pAC->SlowPathLock, Flags);
+
+       if ((pAC->RlmtMode != 0) && (pAC->MaxPorts == 0)) {
+               EvPara.Para32[0] = pAC->RlmtNets;
+               EvPara.Para32[1] = -1;
+               SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_SET_NETS,
+                       EvPara);
+               EvPara.Para32[0] = pAC->RlmtMode;
+               EvPara.Para32[1] = 0;
+               SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_MODE_CHANGE,
+                       EvPara);
+       }
+
+       EvPara.Para32[0] = pNet->NetNr;
+       EvPara.Para32[1] = -1;
+       SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_START, EvPara);
+       SkEventDispatcher(pAC, pAC->IoBase);
+       spin_unlock_irqrestore(&pAC->SlowPathLock, Flags);
+
+       pAC->MaxPorts++;
+
+
+       SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY,
+               ("SkGeOpen suceeded\n"));
+
+       return (0);
+} /* SkGeOpen */
+
+
+/****************************************************************************
+ *
+ *     SkGeClose - Stop initialized adapter
+ *
+ * Description:
+ *     Close initialized adapter.
+ *
+ * Returns:
+ *     0 - on success
+ *     error code - on error
+ */
+static int SkGeClose(
+struct SK_NET_DEVICE   *dev)
+{
+       DEV_NET         *pNet;
+       DEV_NET         *newPtrNet;
+       SK_AC           *pAC;
+
+       unsigned long   Flags;          /* for spin lock */
+       int             i;
+       int             PortIdx;
+       SK_EVPARA       EvPara;
+
+       SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY,
+               ("SkGeClose: pAC=0x%lX ", (unsigned long)pAC));
+
+       pNet = netdev_priv(dev);
+       pAC = pNet->pAC;
+
+#ifdef SK_DIAG_SUPPORT
+       if (pAC->DiagModeActive == DIAG_ACTIVE) {
+               if (pAC->DiagFlowCtrl == SK_FALSE) {
+                       /* 
+                       ** notify that the interface which has been closed
+                       ** by operator interaction must not be started up 
+                       ** again when the DIAG has finished. 
+                       */
+                       newPtrNet = netdev_priv(pAC->dev[0]);
+                       if (newPtrNet == pNet) {
+                               pAC->WasIfUp[0] = SK_FALSE;
+                       } else {
+                               pAC->WasIfUp[1] = SK_FALSE;
+                       }
+                       return 0; /* return to system everything is fine... */
+               } else {
+                       pAC->DiagFlowCtrl = SK_FALSE;
+               }
+       }
+#endif
+
+       netif_stop_queue(dev);
+
+       if (pAC->RlmtNets == 1)
+               PortIdx = pAC->ActivePort;
+       else
+               PortIdx = pNet->NetNr;
+
+        StopDrvCleanupTimer(pAC);
+
+       /*
+        * Clear multicast table, promiscuous mode ....
+        */
+       SkAddrMcClear(pAC, pAC->IoBase, PortIdx, 0);
+       SkAddrPromiscuousChange(pAC, pAC->IoBase, PortIdx,
+               SK_PROM_MODE_NONE);
+
+       if (pAC->MaxPorts == 1) {
+               spin_lock_irqsave(&pAC->SlowPathLock, Flags);
+               /* disable interrupts */
+               SK_OUT32(pAC->IoBase, B0_IMSK, 0);
+               EvPara.Para32[0] = pNet->NetNr;
+               EvPara.Para32[1] = -1;
+               SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_STOP, EvPara);
+               SkEventDispatcher(pAC, pAC->IoBase);
+               SK_OUT32(pAC->IoBase, B0_IMSK, 0);
+               /* stop the hardware */
+               SkGeDeInit(pAC, pAC->IoBase);
+               pAC->BoardLevel = SK_INIT_DATA;
+               spin_unlock_irqrestore(&pAC->SlowPathLock, Flags);
+       } else {
+
+               spin_lock_irqsave(&pAC->SlowPathLock, Flags);
+               EvPara.Para32[0] = pNet->NetNr;
+               EvPara.Para32[1] = -1;
+               SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_STOP, EvPara);
+               SkPnmiEvent(pAC, pAC->IoBase, SK_PNMI_EVT_XMAC_RESET, EvPara);
+               SkEventDispatcher(pAC, pAC->IoBase);
+               spin_unlock_irqrestore(&pAC->SlowPathLock, Flags);
+               
+               /* Stop port */
+               spin_lock_irqsave(&pAC->TxPort[pNet->PortNr]
+                       [TX_PRIO_LOW].TxDesRingLock, Flags);
+               SkGeStopPort(pAC, pAC->IoBase, pNet->PortNr,
+                       SK_STOP_ALL, SK_HARD_RST);
+               spin_unlock_irqrestore(&pAC->TxPort[pNet->PortNr]
+                       [TX_PRIO_LOW].TxDesRingLock, Flags);
+       }
+
+       if (pAC->RlmtNets == 1) {
+               /* clear all descriptor rings */
+               for (i=0; i<pAC->GIni.GIMacsFound; i++) {
+                       ReceiveIrq(pAC, &pAC->RxPort[i], SK_TRUE);
+                       ClearRxRing(pAC, &pAC->RxPort[i]);
+                       ClearTxRing(pAC, &pAC->TxPort[i][TX_PRIO_LOW]);
+               }
+       } else {
+               /* clear port descriptor rings */
+               ReceiveIrq(pAC, &pAC->RxPort[pNet->PortNr], SK_TRUE);
+               ClearRxRing(pAC, &pAC->RxPort[pNet->PortNr]);
+               ClearTxRing(pAC, &pAC->TxPort[pNet->PortNr][TX_PRIO_LOW]);
+       }
+
+       SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY,
+               ("SkGeClose: done "));
+
+       SK_MEMSET(&(pAC->PnmiBackup), 0, sizeof(SK_PNMI_STRUCT_DATA));
+       SK_MEMCPY(&(pAC->PnmiBackup), &(pAC->PnmiStruct), 
+                       sizeof(SK_PNMI_STRUCT_DATA));
+
+       pAC->MaxPorts--;
+
+       return (0);
+} /* SkGeClose */
+
+
+/*****************************************************************************
+ *
+ *     SkGeXmit - Linux frame transmit function
+ *
+ * Description:
+ *     The system calls this function to send frames onto the wire.
+ *     It puts the frame in the tx descriptor ring. If the ring is
+ *     full then, the 'tbusy' flag is set.
+ *
+ * Returns:
+ *     0, if everything is ok
+ *     !=0, on error
+ * WARNING: returning 1 in 'tbusy' case caused system crashes (double
+ *     allocated skb's) !!!
+ */
+static int SkGeXmit(struct sk_buff *skb, struct SK_NET_DEVICE *dev)
+{
+DEV_NET                *pNet;
+SK_AC          *pAC;
+int                    Rc;     /* return code of XmitFrame */
+
+       pNet = netdev_priv(dev);
+       pAC = pNet->pAC;
+
+       if ((!skb_shinfo(skb)->nr_frags) ||
+               (pAC->GIni.GIChipId == CHIP_ID_GENESIS)) {
+               /* Don't activate scatter-gather and hardware checksum */
+
+               if (pAC->RlmtNets == 2)
+                       Rc = XmitFrame(
+                               pAC,
+                               &pAC->TxPort[pNet->PortNr][TX_PRIO_LOW],
+                               skb);
+               else
+                       Rc = XmitFrame(
+                               pAC,
+                               &pAC->TxPort[pAC->ActivePort][TX_PRIO_LOW],
+                               skb);
+       } else {
+               /* scatter-gather and hardware TCP checksumming anabled*/
+               if (pAC->RlmtNets == 2)
+                       Rc = XmitFrameSG(
+                               pAC,
+                               &pAC->TxPort[pNet->PortNr][TX_PRIO_LOW],
+                               skb);
+               else
+                       Rc = XmitFrameSG(
+                               pAC,
+                               &pAC->TxPort[pAC->ActivePort][TX_PRIO_LOW],
+                               skb);
+       }
+
+       /* Transmitter out of resources? */
+       if (Rc <= 0) {
+               netif_stop_queue(dev);
+       }
+
+       /* If not taken, give buffer ownership back to the
+        * queueing layer.
+        */
+       if (Rc < 0)
+               return (1);
+
+       dev->trans_start = jiffies;
+       return (0);
+} /* SkGeXmit */
+
+
+/*****************************************************************************
+ *
+ *     XmitFrame - fill one socket buffer into the transmit ring
+ *
+ * Description:
+ *     This function puts a message into the transmit descriptor ring
+ *     if there is a descriptors left.
+ *     Linux skb's consist of only one continuous buffer.
+ *     The first step locks the ring. It is held locked
+ *     all time to avoid problems with SWITCH_../PORT_RESET.
+ *     Then the descriptoris allocated.
+ *     The second part is linking the buffer to the descriptor.
+ *     At the very last, the Control field of the descriptor
+ *     is made valid for the BMU and a start TX command is given
+ *     if necessary.
+ *
+ * Returns:
+ *     > 0 - on succes: the number of bytes in the message
+ *     = 0 - on resource shortage: this frame sent or dropped, now
+ *             the ring is full ( -> set tbusy)
+ *     < 0 - on failure: other problems ( -> return failure to upper layers)
+ */
+static int XmitFrame(
+SK_AC          *pAC,           /* pointer to adapter context           */
+TX_PORT                *pTxPort,       /* pointer to struct of port to send to */
+struct sk_buff *pMessage)      /* pointer to send-message              */
+{
+       TXD             *pTxd;          /* the rxd to fill */
+       TXD             *pOldTxd;
+       unsigned long    Flags;
+       SK_U64           PhysAddr;
+       int              BytesSend = pMessage->len;
+
+       SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_TX_PROGRESS, ("X"));
+
+       spin_lock_irqsave(&pTxPort->TxDesRingLock, Flags);
+#ifndef USE_TX_COMPLETE
+       FreeTxDescriptors(pAC, pTxPort);
+#endif
+       if (pTxPort->TxdRingFree == 0) {
+               /* 
+               ** no enough free descriptors in ring at the moment.
+               ** Maybe free'ing some old one help?
+               */
+               FreeTxDescriptors(pAC, pTxPort);
+               if (pTxPort->TxdRingFree == 0) {
+                       spin_unlock_irqrestore(&pTxPort->TxDesRingLock, Flags);
+                       SK_PNMI_CNT_NO_TX_BUF(pAC, pTxPort->PortIndex);
+                       SK_DBG_MSG(NULL, SK_DBGMOD_DRV,
+                               SK_DBGCAT_DRV_TX_PROGRESS,
+                               ("XmitFrame failed\n"));
+                       /* 
+                       ** the desired message can not be sent
+                       ** Because tbusy seems to be set, the message 
+                       ** should not be freed here. It will be used 
+                       ** by the scheduler of the ethernet handler 
+                       */
+                       return (-1);
+               }
+       }
+
+       /*
+       ** If the passed socket buffer is of smaller MTU-size than 60,
+       ** copy everything into new buffer and fill all bytes between
+       ** the original packet end and the new packet end of 60 with 0x00.
+       ** This is to resolve faulty padding by the HW with 0xaa bytes.
+       */
+       if (BytesSend < C_LEN_ETHERNET_MINSIZE) {
+               if (skb_padto(pMessage, C_LEN_ETHERNET_MINSIZE)) {
+                       spin_unlock_irqrestore(&pTxPort->TxDesRingLock, Flags);
+                       return 0;
+               }
+               pMessage->len = C_LEN_ETHERNET_MINSIZE;
+       }
+
+       /* 
+       ** advance head counter behind descriptor needed for this frame, 
+       ** so that needed descriptor is reserved from that on. The next
+       ** action will be to add the passed buffer to the TX-descriptor
+       */
+       pTxd = pTxPort->pTxdRingHead;
+       pTxPort->pTxdRingHead = pTxd->pNextTxd;
+       pTxPort->TxdRingFree--;
+
+#ifdef SK_DUMP_TX
+       DumpMsg(pMessage, "XmitFrame");
+#endif
+
+       /* 
+       ** First step is to map the data to be sent via the adapter onto
+       ** the DMA memory. Kernel 2.2 uses virt_to_bus(), but kernels 2.4
+       ** and 2.6 need to use pci_map_page() for that mapping.
+       */
+       PhysAddr = (SK_U64) pci_map_page(pAC->PciDev,
+                                       virt_to_page(pMessage->data),
+                                       ((unsigned long) pMessage->data & ~PAGE_MASK),
+                                       pMessage->len,
+                                       PCI_DMA_TODEVICE);
+       pTxd->VDataLow  = (SK_U32) (PhysAddr & 0xffffffff);
+       pTxd->VDataHigh = (SK_U32) (PhysAddr >> 32);
+       pTxd->pMBuf     = pMessage;
+
+       if (pMessage->ip_summed == CHECKSUM_PARTIAL) {
+               u16 hdrlen = skb_transport_offset(pMessage);
+               u16 offset = hdrlen + pMessage->csum_offset;
+
+               if ((ipip_hdr(pMessage)->protocol == IPPROTO_UDP) &&
+                       (pAC->GIni.GIChipRev == 0) &&
+                       (pAC->GIni.GIChipId == CHIP_ID_YUKON)) {
+                       pTxd->TBControl = BMU_TCP_CHECK;
+               } else {
+                       pTxd->TBControl = BMU_UDP_CHECK;
+               }
+
+               pTxd->TcpSumOfs = 0;
+               pTxd->TcpSumSt  = hdrlen;
+               pTxd->TcpSumWr  = offset;
+
+               pTxd->TBControl |= BMU_OWN | BMU_STF | 
+                                  BMU_SW  | BMU_EOF |
+#ifdef USE_TX_COMPLETE
+                                  BMU_IRQ_EOF |
+#endif
+                                  pMessage->len;
+        } else {
+               pTxd->TBControl = BMU_OWN | BMU_STF | BMU_CHECK | 
+                                 BMU_SW  | BMU_EOF |
+#ifdef USE_TX_COMPLETE
+                                  BMU_IRQ_EOF |
+#endif
+                       pMessage->len;
+       }
+
+       /* 
+       ** If previous descriptor already done, give TX start cmd 
+       */
+       pOldTxd = xchg(&pTxPort->pTxdRingPrev, pTxd);
+       if ((pOldTxd->TBControl & BMU_OWN) == 0) {
+               SK_OUT8(pTxPort->HwAddr, Q_CSR, CSR_START);
+       }       
+
+       /* 
+       ** after releasing the lock, the skb may immediately be free'd 
+       */
+       spin_unlock_irqrestore(&pTxPort->TxDesRingLock, Flags);
+       if (pTxPort->TxdRingFree != 0) {
+               return (BytesSend);
+       } else {
+               return (0);
+       }
+
+} /* XmitFrame */
+
+/*****************************************************************************
+ *
+ *     XmitFrameSG - fill one socket buffer into the transmit ring
+ *                (use SG and TCP/UDP hardware checksumming)
+ *
+ * Description:
+ *     This function puts a message into the transmit descriptor ring
+ *     if there is a descriptors left.
+ *
+ * Returns:
+ *     > 0 - on succes: the number of bytes in the message
+ *     = 0 - on resource shortage: this frame sent or dropped, now
+ *             the ring is full ( -> set tbusy)
+ *     < 0 - on failure: other problems ( -> return failure to upper layers)
+ */
+static int XmitFrameSG(
+SK_AC          *pAC,           /* pointer to adapter context           */
+TX_PORT                *pTxPort,       /* pointer to struct of port to send to */
+struct sk_buff *pMessage)      /* pointer to send-message              */
+{
+
+       TXD             *pTxd;
+       TXD             *pTxdFst;
+       TXD             *pTxdLst;
+       int              CurrFrag;
+       int              BytesSend;
+       skb_frag_t      *sk_frag;
+       SK_U64           PhysAddr;
+       unsigned long    Flags;
+       SK_U32           Control;
+
+       spin_lock_irqsave(&pTxPort->TxDesRingLock, Flags);
+#ifndef USE_TX_COMPLETE
+       FreeTxDescriptors(pAC, pTxPort);
+#endif
+       if ((skb_shinfo(pMessage)->nr_frags +1) > pTxPort->TxdRingFree) {
+               FreeTxDescriptors(pAC, pTxPort);
+               if ((skb_shinfo(pMessage)->nr_frags + 1) > pTxPort->TxdRingFree) {
+                       spin_unlock_irqrestore(&pTxPort->TxDesRingLock, Flags);
+                       SK_PNMI_CNT_NO_TX_BUF(pAC, pTxPort->PortIndex);
+                       SK_DBG_MSG(NULL, SK_DBGMOD_DRV,
+                               SK_DBGCAT_DRV_TX_PROGRESS,
+                               ("XmitFrameSG failed - Ring full\n"));
+                               /* this message can not be sent now */
+                       return(-1);
+               }
+       }
+
+       pTxd      = pTxPort->pTxdRingHead;
+       pTxdFst   = pTxd;
+       pTxdLst   = pTxd;
+       BytesSend = 0;
+
+       /* 
+       ** Map the first fragment (header) into the DMA-space
+       */
+       PhysAddr = (SK_U64) pci_map_page(pAC->PciDev,
+                       virt_to_page(pMessage->data),
+                       ((unsigned long) pMessage->data & ~PAGE_MASK),
+                       skb_headlen(pMessage),
+                       PCI_DMA_TODEVICE);
+
+       pTxd->VDataLow  = (SK_U32) (PhysAddr & 0xffffffff);
+       pTxd->VDataHigh = (SK_U32) (PhysAddr >> 32);
+
+       /* 
+       ** Does the HW need to evaluate checksum for TCP or UDP packets? 
+       */
+       if (pMessage->ip_summed == CHECKSUM_PARTIAL) {
+               u16 hdrlen = skb_transport_offset(pMessage);
+               u16 offset = hdrlen + pMessage->csum_offset;
+
+               Control = BMU_STFWD;
+
+               /* 
+               ** We have to use the opcode for tcp here,  because the
+               ** opcode for udp is not working in the hardware yet 
+               ** (Revision 2.0)
+               */
+               if ((ipip_hdr(pMessage)->protocol == IPPROTO_UDP) &&
+                       (pAC->GIni.GIChipRev == 0) &&
+                       (pAC->GIni.GIChipId == CHIP_ID_YUKON)) {
+                       Control |= BMU_TCP_CHECK;
+               } else {
+                       Control |= BMU_UDP_CHECK;
+               }
+
+               pTxd->TcpSumOfs = 0;
+               pTxd->TcpSumSt  = hdrlen;
+               pTxd->TcpSumWr  = offset;
+       } else
+               Control = BMU_CHECK | BMU_SW;
+
+       pTxd->TBControl = BMU_STF | Control | skb_headlen(pMessage);
+
+       pTxd = pTxd->pNextTxd;
+       pTxPort->TxdRingFree--;
+       BytesSend += skb_headlen(pMessage);
+
+       /* 
+       ** Browse over all SG fragments and map each of them into the DMA space
+       */
+       for (CurrFrag = 0; CurrFrag < skb_shinfo(pMessage)->nr_frags; CurrFrag++) {
+               sk_frag = &skb_shinfo(pMessage)->frags[CurrFrag];
+               /* 
+               ** we already have the proper value in entry
+               */
+               PhysAddr = (SK_U64) pci_map_page(pAC->PciDev,
+                                                sk_frag->page,
+                                                sk_frag->page_offset,
+                                                sk_frag->size,
+                                                PCI_DMA_TODEVICE);
+
+               pTxd->VDataLow  = (SK_U32) (PhysAddr & 0xffffffff);
+               pTxd->VDataHigh = (SK_U32) (PhysAddr >> 32);
+               pTxd->pMBuf     = pMessage;
+               
+               pTxd->TBControl = Control | BMU_OWN | sk_frag->size;
+
+               /* 
+               ** Do we have the last fragment? 
+               */
+               if( (CurrFrag+1) == skb_shinfo(pMessage)->nr_frags )  {
+#ifdef USE_TX_COMPLETE
+                       pTxd->TBControl |= BMU_EOF | BMU_IRQ_EOF;
+#else
+                       pTxd->TBControl |= BMU_EOF;
+#endif
+                       pTxdFst->TBControl |= BMU_OWN | BMU_SW;
+               }
+               pTxdLst = pTxd;
+               pTxd    = pTxd->pNextTxd;
+               pTxPort->TxdRingFree--;
+               BytesSend += sk_frag->size;
+       }
+
+       /* 
+       ** If previous descriptor already done, give TX start cmd 
+       */
+       if ((pTxPort->pTxdRingPrev->TBControl & BMU_OWN) == 0) {
+               SK_OUT8(pTxPort->HwAddr, Q_CSR, CSR_START);
+       }
+
+       pTxPort->pTxdRingPrev = pTxdLst;
+       pTxPort->pTxdRingHead = pTxd;
+
+       spin_unlock_irqrestore(&pTxPort->TxDesRingLock, Flags);
+
+       if (pTxPort->TxdRingFree > 0) {
+               return (BytesSend);
+       } else {
+               return (0);
+       }
+}
+
+/*****************************************************************************
+ *
+ *     FreeTxDescriptors - release descriptors from the descriptor ring
+ *
+ * Description:
+ *     This function releases descriptors from a transmit ring if they
+ *     have been sent by the BMU.
+ *     If a descriptors is sent, it can be freed and the message can
+ *     be freed, too.
+ *     The SOFTWARE controllable bit is used to prevent running around a
+ *     completely free ring for ever. If this bit is no set in the
+ *     frame (by XmitFrame), this frame has never been sent or is
+ *     already freed.
+ *     The Tx descriptor ring lock must be held while calling this function !!!
+ *
+ * Returns:
+ *     none
+ */
+static void FreeTxDescriptors(
+SK_AC  *pAC,           /* pointer to the adapter context */
+TX_PORT        *pTxPort)       /* pointer to destination port structure */
+{
+TXD    *pTxd;          /* pointer to the checked descriptor */
+TXD    *pNewTail;      /* pointer to 'end' of the ring */
+SK_U32 Control;        /* TBControl field of descriptor */
+SK_U64 PhysAddr;       /* address of DMA mapping */
+
+       pNewTail = pTxPort->pTxdRingTail;
+       pTxd     = pNewTail;
+       /*
+       ** loop forever; exits if BMU_SW bit not set in start frame
+       ** or BMU_OWN bit set in any frame
+       */
+       while (1) {
+               Control = pTxd->TBControl;
+               if ((Control & BMU_SW) == 0) {
+                       /*
+                       ** software controllable bit is set in first
+                       ** fragment when given to BMU. Not set means that
+                       ** this fragment was never sent or is already
+                       ** freed ( -> ring completely free now).
+                       */
+                       pTxPort->pTxdRingTail = pTxd;
+                       netif_wake_queue(pAC->dev[pTxPort->PortIndex]);
+                       return;
+               }
+               if (Control & BMU_OWN) {
+                       pTxPort->pTxdRingTail = pTxd;
+                       if (pTxPort->TxdRingFree > 0) {
+                               netif_wake_queue(pAC->dev[pTxPort->PortIndex]);
+                       }
+                       return;
+               }
+               
+               /* 
+               ** release the DMA mapping, because until not unmapped
+               ** this buffer is considered being under control of the
+               ** adapter card!
+               */
+               PhysAddr = ((SK_U64) pTxd->VDataHigh) << (SK_U64) 32;
+               PhysAddr |= (SK_U64) pTxd->VDataLow;
+               pci_unmap_page(pAC->PciDev, PhysAddr,
+                                pTxd->pMBuf->len,
+                                PCI_DMA_TODEVICE);
+
+               if (Control & BMU_EOF)
+                       DEV_KFREE_SKB_ANY(pTxd->pMBuf); /* free message */
+
+               pTxPort->TxdRingFree++;
+               pTxd->TBControl &= ~BMU_SW;
+               pTxd = pTxd->pNextTxd; /* point behind fragment with EOF */
+       } /* while(forever) */
+} /* FreeTxDescriptors */
+
+/*****************************************************************************
+ *
+ *     FillRxRing - fill the receive ring with valid descriptors
+ *
+ * Description:
+ *     This function fills the receive ring descriptors with data
+ *     segments and makes them valid for the BMU.
+ *     The active ring is filled completely, if possible.
+ *     The non-active ring is filled only partial to save memory.
+ *
+ * Description of rx ring structure:
+ *     head - points to the descriptor which will be used next by the BMU
+ *     tail - points to the next descriptor to give to the BMU
+ *     
+ * Returns:    N/A
+ */
+static void FillRxRing(
+SK_AC          *pAC,           /* pointer to the adapter context */
+RX_PORT                *pRxPort)       /* ptr to port struct for which the ring
+                                  should be filled */
+{
+unsigned long  Flags;
+
+       spin_lock_irqsave(&pRxPort->RxDesRingLock, Flags);
+       while (pRxPort->RxdRingFree > pRxPort->RxFillLimit) {
+               if(!FillRxDescriptor(pAC, pRxPort))
+                       break;
+       }
+       spin_unlock_irqrestore(&pRxPort->RxDesRingLock, Flags);
+} /* FillRxRing */
+
+
+/*****************************************************************************
+ *
+ *     FillRxDescriptor - fill one buffer into the receive ring
+ *
+ * Description:
+ *     The function allocates a new receive buffer and
+ *     puts it into the next descriptor.
+ *
+ * Returns:
+ *     SK_TRUE - a buffer was added to the ring
+ *     SK_FALSE - a buffer could not be added
+ */
+static SK_BOOL FillRxDescriptor(
+SK_AC          *pAC,           /* pointer to the adapter context struct */
+RX_PORT                *pRxPort)       /* ptr to port struct of ring to fill */
+{
+struct sk_buff *pMsgBlock;     /* pointer to a new message block */
+RXD            *pRxd;          /* the rxd to fill */
+SK_U16         Length;         /* data fragment length */
+SK_U64         PhysAddr;       /* physical address of a rx buffer */
+
+       pMsgBlock = alloc_skb(pAC->RxBufSize, GFP_ATOMIC);
+       if (pMsgBlock == NULL) {
+               SK_DBG_MSG(NULL, SK_DBGMOD_DRV,
+                       SK_DBGCAT_DRV_ENTRY,
+                       ("%s: Allocation of rx buffer failed !\n",
+                       pAC->dev[pRxPort->PortIndex]->name));
+               SK_PNMI_CNT_NO_RX_BUF(pAC, pRxPort->PortIndex);
+               return(SK_FALSE);
+       }
+       skb_reserve(pMsgBlock, 2); /* to align IP frames */
+       /* skb allocated ok, so add buffer */
+       pRxd = pRxPort->pRxdRingTail;
+       pRxPort->pRxdRingTail = pRxd->pNextRxd;
+       pRxPort->RxdRingFree--;
+       Length = pAC->RxBufSize;
+       PhysAddr = (SK_U64) pci_map_page(pAC->PciDev,
+               virt_to_page(pMsgBlock->data),
+               ((unsigned long) pMsgBlock->data &
+               ~PAGE_MASK),
+               pAC->RxBufSize - 2,
+               PCI_DMA_FROMDEVICE);
+
+       pRxd->VDataLow  = (SK_U32) (PhysAddr & 0xffffffff);
+       pRxd->VDataHigh = (SK_U32) (PhysAddr >> 32);
+       pRxd->pMBuf     = pMsgBlock;
+       pRxd->RBControl = BMU_OWN       | 
+                         BMU_STF       | 
+                         BMU_IRQ_EOF   | 
+                         BMU_TCP_CHECK | 
+                         Length;
+       return (SK_TRUE);
+
+} /* FillRxDescriptor */
+
+
+/*****************************************************************************
+ *
+ *     ReQueueRxBuffer - fill one buffer back into the receive ring
+ *
+ * Description:
+ *     Fill a given buffer back into the rx ring. The buffer
+ *     has been previously allocated and aligned, and its phys.
+ *     address calculated, so this is no more necessary.
+ *
+ * Returns: N/A
+ */
+static void ReQueueRxBuffer(
+SK_AC          *pAC,           /* pointer to the adapter context struct */
+RX_PORT                *pRxPort,       /* ptr to port struct of ring to fill */
+struct sk_buff *pMsg,          /* pointer to the buffer */
+SK_U32         PhysHigh,       /* phys address high dword */
+SK_U32         PhysLow)        /* phys address low dword */
+{
+RXD            *pRxd;          /* the rxd to fill */
+SK_U16         Length;         /* data fragment length */
+
+       pRxd = pRxPort->pRxdRingTail;
+       pRxPort->pRxdRingTail = pRxd->pNextRxd;
+       pRxPort->RxdRingFree--;
+       Length = pAC->RxBufSize;
+
+       pRxd->VDataLow  = PhysLow;
+       pRxd->VDataHigh = PhysHigh;
+       pRxd->pMBuf     = pMsg;
+       pRxd->RBControl = BMU_OWN       | 
+                         BMU_STF       |
+                         BMU_IRQ_EOF   | 
+                         BMU_TCP_CHECK | 
+                         Length;
+       return;
+} /* ReQueueRxBuffer */
+
+/*****************************************************************************
+ *
+ *     ReceiveIrq - handle a receive IRQ
+ *
+ * Description:
+ *     This function is called when a receive IRQ is set.
+ *     It walks the receive descriptor ring and sends up all
+ *     frames that are complete.
+ *
+ * Returns:    N/A
+ */
+static void ReceiveIrq(
+       SK_AC           *pAC,                   /* pointer to adapter context */
+       RX_PORT         *pRxPort,               /* pointer to receive port struct */
+       SK_BOOL         SlowPathLock)   /* indicates if SlowPathLock is needed */
+{
+RXD                            *pRxd;                  /* pointer to receive descriptors */
+SK_U32                 Control;                /* control field of descriptor */
+struct sk_buff *pMsg;                  /* pointer to message holding frame */
+struct sk_buff *pNewMsg;               /* pointer to a new message for copying frame */
+int                            FrameLength;    /* total length of received frame */
+SK_MBUF                        *pRlmtMbuf;             /* ptr to a buffer for giving a frame to rlmt */
+SK_EVPARA              EvPara;                 /* an event parameter union */  
+unsigned long  Flags;                  /* for spin lock */
+int                            PortIndex = pRxPort->PortIndex;
+unsigned int   Offset;
+unsigned int   NumBytes;
+unsigned int   ForRlmt;
+SK_BOOL                        IsBc;
+SK_BOOL                        IsMc;
+SK_BOOL  IsBadFrame;                   /* Bad frame */
+
+SK_U32                 FrameStat;
+SK_U64                 PhysAddr;
+
+rx_start:      
+       /* do forever; exit if BMU_OWN found */
+       for ( pRxd = pRxPort->pRxdRingHead ;
+                 pRxPort->RxdRingFree < pAC->RxDescrPerRing ;
+                 pRxd = pRxd->pNextRxd,
+                 pRxPort->pRxdRingHead = pRxd,
+                 pRxPort->RxdRingFree ++) {
+
+               /*
+                * For a better understanding of this loop
+                * Go through every descriptor beginning at the head
+                * Please note: the ring might be completely received so the OWN bit
+                * set is not a good crirteria to leave that loop.
+                * Therefore the RingFree counter is used.
+                * On entry of this loop pRxd is a pointer to the Rxd that needs
+                * to be checked next.
+                */
+
+               Control = pRxd->RBControl;
+       
+               /* check if this descriptor is ready */
+               if ((Control & BMU_OWN) != 0) {
+                       /* this descriptor is not yet ready */
+                       /* This is the usual end of the loop */
+                       /* We don't need to start the ring again */
+                       FillRxRing(pAC, pRxPort);
+                       return;
+               }
+                pAC->DynIrqModInfo.NbrProcessedDescr++;
+
+               /* get length of frame and check it */
+               FrameLength = Control & BMU_BBC;
+               if (FrameLength > pAC->RxBufSize) {
+                       goto rx_failed;
+               }
+
+               /* check for STF and EOF */
+               if ((Control & (BMU_STF | BMU_EOF)) != (BMU_STF | BMU_EOF)) {
+                       goto rx_failed;
+               }
+
+               /* here we have a complete frame in the ring */
+               pMsg = pRxd->pMBuf;
+
+               FrameStat = pRxd->FrameStat;
+
+               /* check for frame length mismatch */
+#define XMR_FS_LEN_SHIFT        18
+#define GMR_FS_LEN_SHIFT        16
+               if (pAC->GIni.GIChipId == CHIP_ID_GENESIS) {
+                       if (FrameLength != (SK_U32) (FrameStat >> XMR_FS_LEN_SHIFT)) {
+                               SK_DBG_MSG(NULL, SK_DBGMOD_DRV,
+                                       SK_DBGCAT_DRV_RX_PROGRESS,
+                                       ("skge: Frame length mismatch (%u/%u).\n",
+                                       FrameLength,
+                                       (SK_U32) (FrameStat >> XMR_FS_LEN_SHIFT)));
+                               goto rx_failed;
+                       }
+               }
+               else {
+                       if (FrameLength != (SK_U32) (FrameStat >> GMR_FS_LEN_SHIFT)) {
+                               SK_DBG_MSG(NULL, SK_DBGMOD_DRV,
+                                       SK_DBGCAT_DRV_RX_PROGRESS,
+                                       ("skge: Frame length mismatch (%u/%u).\n",
+                                       FrameLength,
+                                       (SK_U32) (FrameStat >> XMR_FS_LEN_SHIFT)));
+                               goto rx_failed;
+                       }
+               }
+
+               /* Set Rx Status */
+               if (pAC->GIni.GIChipId == CHIP_ID_GENESIS) {
+                       IsBc = (FrameStat & XMR_FS_BC) != 0;
+                       IsMc = (FrameStat & XMR_FS_MC) != 0;
+                       IsBadFrame = (FrameStat &
+                               (XMR_FS_ANY_ERR | XMR_FS_2L_VLAN)) != 0;
+               } else {
+                       IsBc = (FrameStat & GMR_FS_BC) != 0;
+                       IsMc = (FrameStat & GMR_FS_MC) != 0;
+                       IsBadFrame = (((FrameStat & GMR_FS_ANY_ERR) != 0) ||
+                                                       ((FrameStat & GMR_FS_RX_OK) == 0));
+               }
+
+               SK_DBG_MSG(NULL, SK_DBGMOD_DRV, 0,
+                       ("Received frame of length %d on port %d\n",
+                       FrameLength, PortIndex));
+               SK_DBG_MSG(NULL, SK_DBGMOD_DRV, 0,
+                       ("Number of free rx descriptors: %d\n",
+                       pRxPort->RxdRingFree));
+/* DumpMsg(pMsg, "Rx");        */
+
+               if ((Control & BMU_STAT_VAL) != BMU_STAT_VAL || (IsBadFrame)) {
+#if 0
+                       (FrameStat & (XMR_FS_ANY_ERR | XMR_FS_2L_VLAN)) != 0) {
+#endif
+                       /* there is a receive error in this frame */
+                       SK_DBG_MSG(NULL, SK_DBGMOD_DRV,
+                               SK_DBGCAT_DRV_RX_PROGRESS,
+                               ("skge: Error in received frame, dropped!\n"
+                               "Control: %x\nRxStat: %x\n",
+                               Control, FrameStat));
+
+                       ReQueueRxBuffer(pAC, pRxPort, pMsg,
+                               pRxd->VDataHigh, pRxd->VDataLow);
+
+                       continue;
+               }
+
+               /*
+                * if short frame then copy data to reduce memory waste
+                */
+               if ((FrameLength < SK_COPY_THRESHOLD) &&
+                       ((pNewMsg = alloc_skb(FrameLength+2, GFP_ATOMIC)) != NULL)) {
+                       /*
+                        * Short frame detected and allocation successfull
+                        */
+                       /* use new skb and copy data */
+                       skb_reserve(pNewMsg, 2);
+                       skb_put(pNewMsg, FrameLength);
+                       PhysAddr = ((SK_U64) pRxd->VDataHigh) << (SK_U64)32;
+                       PhysAddr |= (SK_U64) pRxd->VDataLow;
+
+                       pci_dma_sync_single_for_cpu(pAC->PciDev,
+                                                   (dma_addr_t) PhysAddr,
+                                                   FrameLength,
+                                                   PCI_DMA_FROMDEVICE);
+                       skb_copy_to_linear_data(pNewMsg, pMsg, FrameLength);
+
+                       pci_dma_sync_single_for_device(pAC->PciDev,
+                                                      (dma_addr_t) PhysAddr,
+                                                      FrameLength,
+                                                      PCI_DMA_FROMDEVICE);
+                       ReQueueRxBuffer(pAC, pRxPort, pMsg,
+                               pRxd->VDataHigh, pRxd->VDataLow);
+
+                       pMsg = pNewMsg;
+
+               }
+               else {
+                       /*
+                        * if large frame, or SKB allocation failed, pass
+                        * the SKB directly to the networking
+                        */
+
+                       PhysAddr = ((SK_U64) pRxd->VDataHigh) << (SK_U64)32;
+                       PhysAddr |= (SK_U64) pRxd->VDataLow;
+
+                       /* release the DMA mapping */
+                       pci_unmap_single(pAC->PciDev,
+                                        PhysAddr,
+                                        pAC->RxBufSize - 2,
+                                        PCI_DMA_FROMDEVICE);
+
+                       /* set length in message */
+                       skb_put(pMsg, FrameLength);
+               } /* frame > SK_COPY_TRESHOLD */
+
+#ifdef USE_SK_RX_CHECKSUM
+               pMsg->csum = pRxd->TcpSums & 0xffff;
+               pMsg->ip_summed = CHECKSUM_COMPLETE;
+#else
+               pMsg->ip_summed = CHECKSUM_NONE;
+#endif
+
+               SK_DBG_MSG(NULL, SK_DBGMOD_DRV, 1,("V"));
+               ForRlmt = SK_RLMT_RX_PROTOCOL;
+#if 0
+               IsBc = (FrameStat & XMR_FS_BC)==XMR_FS_BC;
+#endif
+               SK_RLMT_PRE_LOOKAHEAD(pAC, PortIndex, FrameLength,
+                       IsBc, &Offset, &NumBytes);
+               if (NumBytes != 0) {
+#if 0
+                       IsMc = (FrameStat & XMR_FS_MC)==XMR_FS_MC;
+#endif
+                       SK_RLMT_LOOKAHEAD(pAC, PortIndex,
+                               &pMsg->data[Offset],
+                               IsBc, IsMc, &ForRlmt);
+               }
+               if (ForRlmt == SK_RLMT_RX_PROTOCOL) {
+                                       SK_DBG_MSG(NULL, SK_DBGMOD_DRV, 1,("W"));
+                       /* send up only frames from active port */
+                       if ((PortIndex == pAC->ActivePort) ||
+                               (pAC->RlmtNets == 2)) {
+                               /* frame for upper layer */
+                               SK_DBG_MSG(NULL, SK_DBGMOD_DRV, 1,("U"));
+#ifdef xDEBUG
+                               DumpMsg(pMsg, "Rx");
+#endif
+                               SK_PNMI_CNT_RX_OCTETS_DELIVERED(pAC,
+                                       FrameLength, pRxPort->PortIndex);
+
+                               pMsg->protocol = eth_type_trans(pMsg,
+                                       pAC->dev[pRxPort->PortIndex]);
+                               netif_rx(pMsg);
+                               pAC->dev[pRxPort->PortIndex]->last_rx = jiffies;
+                       }
+                       else {
+                               /* drop frame */
+                               SK_DBG_MSG(NULL, SK_DBGMOD_DRV,
+                                       SK_DBGCAT_DRV_RX_PROGRESS,
+                                       ("D"));
+                               DEV_KFREE_SKB(pMsg);
+                       }
+                       
+               } /* if not for rlmt */
+               else {
+                       /* packet for rlmt */
+                       SK_DBG_MSG(NULL, SK_DBGMOD_DRV,
+                               SK_DBGCAT_DRV_RX_PROGRESS, ("R"));
+                       pRlmtMbuf = SkDrvAllocRlmtMbuf(pAC,
+                               pAC->IoBase, FrameLength);
+                       if (pRlmtMbuf != NULL) {
+                               pRlmtMbuf->pNext = NULL;
+                               pRlmtMbuf->Length = FrameLength;
+                               pRlmtMbuf->PortIdx = PortIndex;
+                               EvPara.pParaPtr = pRlmtMbuf;
+                               memcpy((char*)(pRlmtMbuf->pData),
+                                          (char*)(pMsg->data),
+                                          FrameLength);
+
+                               /* SlowPathLock needed? */
+                               if (SlowPathLock == SK_TRUE) {
+                                       spin_lock_irqsave(&pAC->SlowPathLock, Flags);
+                                       SkEventQueue(pAC, SKGE_RLMT,
+                                               SK_RLMT_PACKET_RECEIVED,
+                                               EvPara);
+                                       pAC->CheckQueue = SK_TRUE;
+                                       spin_unlock_irqrestore(&pAC->SlowPathLock, Flags);
+                               } else {
+                                       SkEventQueue(pAC, SKGE_RLMT,
+                                               SK_RLMT_PACKET_RECEIVED,
+                                               EvPara);
+                                       pAC->CheckQueue = SK_TRUE;
+                               }
+
+                               SK_DBG_MSG(NULL, SK_DBGMOD_DRV,
+                                       SK_DBGCAT_DRV_RX_PROGRESS,
+                                       ("Q"));
+                       }
+                       if ((pAC->dev[pRxPort->PortIndex]->flags &
+                               (IFF_PROMISC | IFF_ALLMULTI)) != 0 ||
+                               (ForRlmt & SK_RLMT_RX_PROTOCOL) ==
+                               SK_RLMT_RX_PROTOCOL) {
+                               pMsg->protocol = eth_type_trans(pMsg,
+                                       pAC->dev[pRxPort->PortIndex]);
+                               netif_rx(pMsg);
+                               pAC->dev[pRxPort->PortIndex]->last_rx = jiffies;
+                       }
+                       else {
+                               DEV_KFREE_SKB(pMsg);
+                       }
+
+               } /* if packet for rlmt */
+       } /* for ... scanning the RXD ring */
+
+       /* RXD ring is empty -> fill and restart */
+       FillRxRing(pAC, pRxPort);
+       /* do not start if called from Close */
+       if (pAC->BoardLevel > SK_INIT_DATA) {
+               ClearAndStartRx(pAC, PortIndex);
+       }
+       return;
+
+rx_failed:
+       /* remove error frame */
+       SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ERROR,
+               ("Schrottdescriptor, length: 0x%x\n", FrameLength));
+
+       /* release the DMA mapping */
+
+       PhysAddr = ((SK_U64) pRxd->VDataHigh) << (SK_U64)32;
+       PhysAddr |= (SK_U64) pRxd->VDataLow;
+       pci_unmap_page(pAC->PciDev,
+                        PhysAddr,
+                        pAC->RxBufSize - 2,
+                        PCI_DMA_FROMDEVICE);
+       DEV_KFREE_SKB_IRQ(pRxd->pMBuf);
+       pRxd->pMBuf = NULL;
+       pRxPort->RxdRingFree++;
+       pRxPort->pRxdRingHead = pRxd->pNextRxd;
+       goto rx_start;
+
+} /* ReceiveIrq */
+
+
+/*****************************************************************************
+ *
+ *     ClearAndStartRx - give a start receive command to BMU, clear IRQ
+ *
+ * Description:
+ *     This function sends a start command and a clear interrupt
+ *     command for one receive queue to the BMU.
+ *
+ * Returns: N/A
+ *     none
+ */
+static void ClearAndStartRx(
+SK_AC  *pAC,           /* pointer to the adapter context */
+int    PortIndex)      /* index of the receive port (XMAC) */
+{
+       SK_OUT8(pAC->IoBase,
+               RxQueueAddr[PortIndex]+Q_CSR,
+               CSR_START | CSR_IRQ_CL_F);
+} /* ClearAndStartRx */
+
+
+/*****************************************************************************
+ *
+ *     ClearTxIrq - give a clear transmit IRQ command to BMU
+ *
+ * Description:
+ *     This function sends a clear tx IRQ command for one
+ *     transmit queue to the BMU.
+ *
+ * Returns: N/A
+ */
+static void ClearTxIrq(
+SK_AC  *pAC,           /* pointer to the adapter context */
+int    PortIndex,      /* index of the transmit port (XMAC) */
+int    Prio)           /* priority or normal queue */
+{
+       SK_OUT8(pAC->IoBase, 
+               TxQueueAddr[PortIndex][Prio]+Q_CSR,
+               CSR_IRQ_CL_F);
+} /* ClearTxIrq */
+
+
+/*****************************************************************************
+ *
+ *     ClearRxRing - remove all buffers from the receive ring
+ *
+ * Description:
+ *     This function removes all receive buffers from the ring.
+ *     The receive BMU must be stopped before calling this function.
+ *
+ * Returns: N/A
+ */
+static void ClearRxRing(
+SK_AC  *pAC,           /* pointer to adapter context */
+RX_PORT        *pRxPort)       /* pointer to rx port struct */
+{
+RXD            *pRxd;  /* pointer to the current descriptor */
+unsigned long  Flags;
+SK_U64         PhysAddr;
+
+       if (pRxPort->RxdRingFree == pAC->RxDescrPerRing) {
+               return;
+       }
+       spin_lock_irqsave(&pRxPort->RxDesRingLock, Flags);
+       pRxd = pRxPort->pRxdRingHead;
+       do {
+               if (pRxd->pMBuf != NULL) {
+
+                       PhysAddr = ((SK_U64) pRxd->VDataHigh) << (SK_U64)32;
+                       PhysAddr |= (SK_U64) pRxd->VDataLow;
+                       pci_unmap_page(pAC->PciDev,
+                                        PhysAddr,
+                                        pAC->RxBufSize - 2,
+                                        PCI_DMA_FROMDEVICE);
+                       DEV_KFREE_SKB(pRxd->pMBuf);
+                       pRxd->pMBuf = NULL;
+               }
+               pRxd->RBControl &= BMU_OWN;
+               pRxd = pRxd->pNextRxd;
+               pRxPort->RxdRingFree++;
+       } while (pRxd != pRxPort->pRxdRingTail);
+       pRxPort->pRxdRingTail = pRxPort->pRxdRingHead;
+       spin_unlock_irqrestore(&pRxPort->RxDesRingLock, Flags);
+} /* ClearRxRing */
+
+/*****************************************************************************
+ *
+ *     ClearTxRing - remove all buffers from the transmit ring
+ *
+ * Description:
+ *     This function removes all transmit buffers from the ring.
+ *     The transmit BMU must be stopped before calling this function
+ *     and transmitting at the upper level must be disabled.
+ *     The BMU own bit of all descriptors is cleared, the rest is
+ *     done by calling FreeTxDescriptors.
+ *
+ * Returns: N/A
+ */
+static void ClearTxRing(
+SK_AC  *pAC,           /* pointer to adapter context */
+TX_PORT        *pTxPort)       /* pointer to tx prt struct */
+{
+TXD            *pTxd;          /* pointer to the current descriptor */
+int            i;
+unsigned long  Flags;
+
+       spin_lock_irqsave(&pTxPort->TxDesRingLock, Flags);
+       pTxd = pTxPort->pTxdRingHead;
+       for (i=0; i<pAC->TxDescrPerRing; i++) {
+               pTxd->TBControl &= ~BMU_OWN;
+               pTxd = pTxd->pNextTxd;
+       }
+       FreeTxDescriptors(pAC, pTxPort);
+       spin_unlock_irqrestore(&pTxPort->TxDesRingLock, Flags);
+} /* ClearTxRing */
+
+/*****************************************************************************
+ *
+ *     SkGeSetMacAddr - Set the hardware MAC address
+ *
+ * Description:
+ *     This function sets the MAC address used by the adapter.
+ *
+ * Returns:
+ *     0, if everything is ok
+ *     !=0, on error
+ */
+static int SkGeSetMacAddr(struct SK_NET_DEVICE *dev, void *p)
+{
+
+DEV_NET *pNet = netdev_priv(dev);
+SK_AC  *pAC = pNet->pAC;
+
+struct sockaddr        *addr = p;
+unsigned long  Flags;
+       
+       SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY,
+               ("SkGeSetMacAddr starts now...\n"));
+       if(netif_running(dev))
+               return -EBUSY;
+
+       memcpy(dev->dev_addr, addr->sa_data,dev->addr_len);
+       
+       spin_lock_irqsave(&pAC->SlowPathLock, Flags);
+
+       if (pAC->RlmtNets == 2)
+               SkAddrOverride(pAC, pAC->IoBase, pNet->NetNr,
+                       (SK_MAC_ADDR*)dev->dev_addr, SK_ADDR_VIRTUAL_ADDRESS);
+       else
+               SkAddrOverride(pAC, pAC->IoBase, pAC->ActivePort,
+                       (SK_MAC_ADDR*)dev->dev_addr, SK_ADDR_VIRTUAL_ADDRESS);
+
+       
+       
+       spin_unlock_irqrestore(&pAC->SlowPathLock, Flags);
+       return 0;
+} /* SkGeSetMacAddr */
+
+
+/*****************************************************************************
+ *
+ *     SkGeSetRxMode - set receive mode
+ *
+ * Description:
+ *     This function sets the receive mode of an adapter. The adapter
+ *     supports promiscuous mode, allmulticast mode and a number of
+ *     multicast addresses. If more multicast addresses the available
+ *     are selected, a hash function in the hardware is used.
+ *
+ * Returns:
+ *     0, if everything is ok
+ *     !=0, on error
+ */
+static void SkGeSetRxMode(struct SK_NET_DEVICE *dev)
+{
+
+DEV_NET                *pNet;
+SK_AC          *pAC;
+
+struct dev_mc_list     *pMcList;
+int                    i;
+int                    PortIdx;
+unsigned long          Flags;
+
+       SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY,
+               ("SkGeSetRxMode starts now... "));
+
+       pNet = netdev_priv(dev);
+       pAC = pNet->pAC;
+       if (pAC->RlmtNets == 1)
+               PortIdx = pAC->ActivePort;
+       else
+               PortIdx = pNet->NetNr;
+
+       spin_lock_irqsave(&pAC->SlowPathLock, Flags);
+       if (dev->flags & IFF_PROMISC) {
+               SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY,
+                       ("PROMISCUOUS mode\n"));
+               SkAddrPromiscuousChange(pAC, pAC->IoBase, PortIdx,
+                       SK_PROM_MODE_LLC);
+       } else if (dev->flags & IFF_ALLMULTI) {
+               SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY,
+                       ("ALLMULTI mode\n"));
+               SkAddrPromiscuousChange(pAC, pAC->IoBase, PortIdx,
+                       SK_PROM_MODE_ALL_MC);
+       } else {
+               SkAddrPromiscuousChange(pAC, pAC->IoBase, PortIdx,
+                       SK_PROM_MODE_NONE);
+               SkAddrMcClear(pAC, pAC->IoBase, PortIdx, 0);
+
+               SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY,
+                       ("Number of MC entries: %d ", dev->mc_count));
+               
+               pMcList = dev->mc_list;
+               for (i=0; i<dev->mc_count; i++, pMcList = pMcList->next) {
+                       SkAddrMcAdd(pAC, pAC->IoBase, PortIdx,
+                               (SK_MAC_ADDR*)pMcList->dmi_addr, 0);
+                       SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_MCA,
+                               ("%02x:%02x:%02x:%02x:%02x:%02x\n",
+                               pMcList->dmi_addr[0],
+                               pMcList->dmi_addr[1],
+                               pMcList->dmi_addr[2],
+                               pMcList->dmi_addr[3],
+                               pMcList->dmi_addr[4],
+                               pMcList->dmi_addr[5]));
+               }
+               SkAddrMcUpdate(pAC, pAC->IoBase, PortIdx);
+       }
+       spin_unlock_irqrestore(&pAC->SlowPathLock, Flags);
+       
+       return;
+} /* SkGeSetRxMode */
+
+
+/*****************************************************************************
+ *
+ *     SkGeChangeMtu - set the MTU to another value
+ *
+ * Description:
+ *     This function sets is called whenever the MTU size is changed
+ *     (ifconfig mtu xxx dev ethX). If the MTU is bigger than standard
+ *     ethernet MTU size, long frame support is activated.
+ *
+ * Returns:
+ *     0, if everything is ok
+ *     !=0, on error
+ */
+static int SkGeChangeMtu(struct SK_NET_DEVICE *dev, int NewMtu)
+{
+DEV_NET                *pNet;
+struct net_device *pOtherDev;
+SK_AC          *pAC;
+unsigned long  Flags;
+int            i;
+SK_EVPARA      EvPara;
+
+       SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY,
+               ("SkGeChangeMtu starts now...\n"));
+
+       pNet = netdev_priv(dev);
+       pAC  = pNet->pAC;
+
+       if ((NewMtu < 68) || (NewMtu > SK_JUMBO_MTU)) {
+               return -EINVAL;
+       }
+
+       if(pAC->BoardLevel != SK_INIT_RUN) {
+               return -EINVAL;
+       }
+
+#ifdef SK_DIAG_SUPPORT
+       if (pAC->DiagModeActive == DIAG_ACTIVE) {
+               if (pAC->DiagFlowCtrl == SK_FALSE) {
+                       return -1; /* still in use, deny any actions of MTU */
+               } else {
+                       pAC->DiagFlowCtrl = SK_FALSE;
+               }
+       }
+#endif
+
+       pOtherDev = pAC->dev[1 - pNet->NetNr];
+
+       if ( netif_running(pOtherDev) && (pOtherDev->mtu > 1500)
+            && (NewMtu <= 1500))
+               return 0;
+
+       pAC->RxBufSize = NewMtu + 32;
+       dev->mtu = NewMtu;
+
+       SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY,
+               ("New MTU: %d\n", NewMtu));
+
+       /* 
+       ** Prevent any reconfiguration while changing the MTU 
+       ** by disabling any interrupts 
+       */
+       SK_OUT32(pAC->IoBase, B0_IMSK, 0);
+       spin_lock_irqsave(&pAC->SlowPathLock, Flags);
+
+       /* 
+       ** Notify RLMT that any ports are to be stopped
+       */
+       EvPara.Para32[0] =  0;
+       EvPara.Para32[1] = -1;
+       if ((pAC->GIni.GIMacsFound == 2 ) && (pAC->RlmtNets == 2)) {
+               SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_STOP, EvPara);
+               EvPara.Para32[0] =  1;
+               SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_STOP, EvPara);
+       } else {
+               SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_STOP, EvPara);
+       }
+
+       /*
+       ** After calling the SkEventDispatcher(), RLMT is aware about
+       ** the stopped ports -> configuration can take place!
+       */
+       SkEventDispatcher(pAC, pAC->IoBase);
+
+       for (i=0; i<pAC->GIni.GIMacsFound; i++) {
+               spin_lock(&pAC->TxPort[i][TX_PRIO_LOW].TxDesRingLock);
+               netif_stop_queue(pAC->dev[i]);
+
+       }
+
+       /*
+       ** Depending on the desired MTU size change, a different number of 
+       ** RX buffers need to be allocated
+       */
+       if (NewMtu > 1500) {
+           /* 
+           ** Use less rx buffers 
+           */
+           for (i=0; i<pAC->GIni.GIMacsFound; i++) {
+               if ((pAC->GIni.GIMacsFound == 2 ) && (pAC->RlmtNets == 2)) {
+                   pAC->RxPort[i].RxFillLimit =  pAC->RxDescrPerRing -
+                                                (pAC->RxDescrPerRing / 4);
+               } else {
+                   if (i == pAC->ActivePort) {
+                       pAC->RxPort[i].RxFillLimit = pAC->RxDescrPerRing - 
+                                                   (pAC->RxDescrPerRing / 4);
+                   } else {
+                       pAC->RxPort[i].RxFillLimit = pAC->RxDescrPerRing - 
+                                                   (pAC->RxDescrPerRing / 10);
+                   }
+               }
+           }
+       } else {
+           /* 
+           ** Use the normal amount of rx buffers 
+           */
+           for (i=0; i<pAC->GIni.GIMacsFound; i++) {
+               if ((pAC->GIni.GIMacsFound == 2 ) && (pAC->RlmtNets == 2)) {
+                   pAC->RxPort[i].RxFillLimit = 1;
+               } else {
+                   if (i == pAC->ActivePort) {
+                       pAC->RxPort[i].RxFillLimit = 1;
+                   } else {
+                       pAC->RxPort[i].RxFillLimit = pAC->RxDescrPerRing -
+                                                   (pAC->RxDescrPerRing / 4);
+                   }
+               }
+           }
+       }
+       
+       SkGeDeInit(pAC, pAC->IoBase);
+
+       /*
+       ** enable/disable hardware support for long frames
+       */
+       if (NewMtu > 1500) {
+// pAC->JumboActivated = SK_TRUE; /* is never set back !!! */
+               pAC->GIni.GIPortUsage = SK_JUMBO_LINK;
+       } else {
+           if ((pAC->GIni.GIMacsFound == 2 ) && (pAC->RlmtNets == 2)) {
+               pAC->GIni.GIPortUsage = SK_MUL_LINK;
+           } else {
+               pAC->GIni.GIPortUsage = SK_RED_LINK;
+           }
+       }
+
+       SkGeInit(   pAC, pAC->IoBase, SK_INIT_IO);
+       SkI2cInit(  pAC, pAC->IoBase, SK_INIT_IO);
+       SkEventInit(pAC, pAC->IoBase, SK_INIT_IO);
+       SkPnmiInit( pAC, pAC->IoBase, SK_INIT_IO);
+       SkAddrInit( pAC, pAC->IoBase, SK_INIT_IO);
+       SkRlmtInit( pAC, pAC->IoBase, SK_INIT_IO);
+       SkTimerInit(pAC, pAC->IoBase, SK_INIT_IO);
+       
+       /*
+       ** tschilling:
+       ** Speed and others are set back to default in level 1 init!
+       */
+       GetConfiguration(pAC);
+       
+       SkGeInit(   pAC, pAC->IoBase, SK_INIT_RUN);
+       SkI2cInit(  pAC, pAC->IoBase, SK_INIT_RUN);
+       SkEventInit(pAC, pAC->IoBase, SK_INIT_RUN);
+       SkPnmiInit( pAC, pAC->IoBase, SK_INIT_RUN);
+       SkAddrInit( pAC, pAC->IoBase, SK_INIT_RUN);
+       SkRlmtInit( pAC, pAC->IoBase, SK_INIT_RUN);
+       SkTimerInit(pAC, pAC->IoBase, SK_INIT_RUN);
+
+       /*
+       ** clear and reinit the rx rings here
+       */
+       for (i=0; i<pAC->GIni.GIMacsFound; i++) {
+               ReceiveIrq(pAC, &pAC->RxPort[i], SK_TRUE);
+               ClearRxRing(pAC, &pAC->RxPort[i]);
+               FillRxRing(pAC, &pAC->RxPort[i]);
+
+               /* 
+               ** Enable transmit descriptor polling
+               */
+               SkGePollTxD(pAC, pAC->IoBase, i, SK_TRUE);
+               FillRxRing(pAC, &pAC->RxPort[i]);
+       };
+
+       SkGeYellowLED(pAC, pAC->IoBase, 1);
+       SkDimEnableModerationIfNeeded(pAC);     
+       SkDimDisplayModerationSettings(pAC);
+
+       netif_start_queue(pAC->dev[pNet->PortNr]);
+       for (i=pAC->GIni.GIMacsFound-1; i>=0; i--) {
+               spin_unlock(&pAC->TxPort[i][TX_PRIO_LOW].TxDesRingLock);
+       }
+
+       /* 
+       ** Enable Interrupts again 
+       */
+       SK_OUT32(pAC->IoBase, B0_IMSK, pAC->GIni.GIValIrqMask);
+       SK_OUT32(pAC->IoBase, B0_HWE_IMSK, IRQ_HWE_MASK);
+
+       SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_START, EvPara);
+       SkEventDispatcher(pAC, pAC->IoBase);
+
+       /* 
+       ** Notify RLMT about the changing and restarting one (or more) ports
+       */
+       if ((pAC->GIni.GIMacsFound == 2 ) && (pAC->RlmtNets == 2)) {
+               EvPara.Para32[0] = pAC->RlmtNets;
+               EvPara.Para32[1] = -1;
+               SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_SET_NETS, EvPara);
+               EvPara.Para32[0] = pNet->PortNr;
+               EvPara.Para32[1] = -1;
+               SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_START, EvPara);
+                       
+               if (netif_running(pOtherDev)) {
+                       DEV_NET *pOtherNet = netdev_priv(pOtherDev);
+                       EvPara.Para32[0] = pOtherNet->PortNr;
+                       SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_START, EvPara);
+               }
+       } else {
+               SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_START, EvPara);
+       }
+
+       SkEventDispatcher(pAC, pAC->IoBase);
+       spin_unlock_irqrestore(&pAC->SlowPathLock, Flags);
+       
+       /*
+       ** While testing this driver with latest kernel 2.5 (2.5.70), it 
+       ** seems as if upper layers have a problem to handle a successful
+       ** return value of '0'. If such a zero is returned, the complete 
+       ** system hangs for several minutes (!), which is in acceptable.
+       **
+       ** Currently it is not clear, what the exact reason for this problem
+       ** is. The implemented workaround for 2.5 is to return the desired 
+       ** new MTU size if all needed changes for the new MTU size where 
+       ** performed. In kernels 2.2 and 2.4, a zero value is returned,
+       ** which indicates the successful change of the mtu-size.
+       */
+       return NewMtu;
+
+} /* SkGeChangeMtu */
+
+
+/*****************************************************************************
+ *
+ *     SkGeStats - return ethernet device statistics
+ *
+ * Description:
+ *     This function return statistic data about the ethernet device
+ *     to the operating system.
+ *
+ * Returns:
+ *     pointer to the statistic structure.
+ */
+static struct net_device_stats *SkGeStats(struct SK_NET_DEVICE *dev)
+{
+DEV_NET *pNet = netdev_priv(dev);
+SK_AC  *pAC = pNet->pAC;
+SK_PNMI_STRUCT_DATA *pPnmiStruct;       /* structure for all Pnmi-Data */
+SK_PNMI_STAT    *pPnmiStat;             /* pointer to virtual XMAC stat. data */
+SK_PNMI_CONF    *pPnmiConf;             /* pointer to virtual link config. */
+unsigned int    Size;                   /* size of pnmi struct */
+unsigned long  Flags;                  /* for spin lock */
+
+       SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY,
+               ("SkGeStats starts now...\n"));
+       pPnmiStruct = &pAC->PnmiStruct;
+
+#ifdef SK_DIAG_SUPPORT
+        if ((pAC->DiagModeActive == DIAG_NOTACTIVE) &&
+                (pAC->BoardLevel == SK_INIT_RUN)) {
+#endif
+        SK_MEMSET(pPnmiStruct, 0, sizeof(SK_PNMI_STRUCT_DATA));
+        spin_lock_irqsave(&pAC->SlowPathLock, Flags);
+        Size = SK_PNMI_STRUCT_SIZE;
+               SkPnmiGetStruct(pAC, pAC->IoBase, pPnmiStruct, &Size, pNet->NetNr);
+        spin_unlock_irqrestore(&pAC->SlowPathLock, Flags);
+#ifdef SK_DIAG_SUPPORT
+       }
+#endif
+
+        pPnmiStat = &pPnmiStruct->Stat[0];
+        pPnmiConf = &pPnmiStruct->Conf[0];
+
+       pAC->stats.rx_packets = (SK_U32) pPnmiStruct->RxDeliveredCts & 0xFFFFFFFF;
+       pAC->stats.tx_packets = (SK_U32) pPnmiStat->StatTxOkCts & 0xFFFFFFFF;
+       pAC->stats.rx_bytes = (SK_U32) pPnmiStruct->RxOctetsDeliveredCts;
+       pAC->stats.tx_bytes = (SK_U32) pPnmiStat->StatTxOctetsOkCts;
+       
+        if (dev->mtu <= 1500) {
+                pAC->stats.rx_errors = (SK_U32) pPnmiStruct->InErrorsCts & 0xFFFFFFFF;
+        } else {
+                pAC->stats.rx_errors = (SK_U32) ((pPnmiStruct->InErrorsCts -
+                        pPnmiStat->StatRxTooLongCts) & 0xFFFFFFFF);
+       }
+
+
+       if (pAC->GIni.GP[0].PhyType == SK_PHY_XMAC && pAC->HWRevision < 12)
+               pAC->stats.rx_errors = pAC->stats.rx_errors - pPnmiStat->StatRxShortsCts;
+
+       pAC->stats.tx_errors = (SK_U32) pPnmiStat->StatTxSingleCollisionCts & 0xFFFFFFFF;
+       pAC->stats.rx_dropped = (SK_U32) pPnmiStruct->RxNoBufCts & 0xFFFFFFFF;
+       pAC->stats.tx_dropped = (SK_U32) pPnmiStruct->TxNoBufCts & 0xFFFFFFFF;
+       pAC->stats.multicast = (SK_U32) pPnmiStat->StatRxMulticastOkCts & 0xFFFFFFFF;
+       pAC->stats.collisions = (SK_U32) pPnmiStat->StatTxSingleCollisionCts & 0xFFFFFFFF;
+
+       /* detailed rx_errors: */
+       pAC->stats.rx_length_errors = (SK_U32) pPnmiStat->StatRxRuntCts & 0xFFFFFFFF;
+       pAC->stats.rx_over_errors = (SK_U32) pPnmiStat->StatRxFifoOverflowCts & 0xFFFFFFFF;
+       pAC->stats.rx_crc_errors = (SK_U32) pPnmiStat->StatRxFcsCts & 0xFFFFFFFF;
+       pAC->stats.rx_frame_errors = (SK_U32) pPnmiStat->StatRxFramingCts & 0xFFFFFFFF;
+       pAC->stats.rx_fifo_errors = (SK_U32) pPnmiStat->StatRxFifoOverflowCts & 0xFFFFFFFF;
+       pAC->stats.rx_missed_errors = (SK_U32) pPnmiStat->StatRxMissedCts & 0xFFFFFFFF;
+
+       /* detailed tx_errors */
+       pAC->stats.tx_aborted_errors = (SK_U32) 0;
+       pAC->stats.tx_carrier_errors = (SK_U32) pPnmiStat->StatTxCarrierCts & 0xFFFFFFFF;
+       pAC->stats.tx_fifo_errors = (SK_U32) pPnmiStat->StatTxFifoUnderrunCts & 0xFFFFFFFF;
+       pAC->stats.tx_heartbeat_errors = (SK_U32) pPnmiStat->StatTxCarrierCts & 0xFFFFFFFF;
+       pAC->stats.tx_window_errors = (SK_U32) 0;
+
+       return(&pAC->stats);
+} /* SkGeStats */
+
+/*
+ * Basic MII register access
+ */
+static int SkGeMiiIoctl(struct net_device *dev,
+                       struct mii_ioctl_data *data, int cmd)
+{
+       DEV_NET *pNet = netdev_priv(dev);
+       SK_AC *pAC = pNet->pAC;
+       SK_IOC IoC = pAC->IoBase;
+       int Port = pNet->PortNr;
+       SK_GEPORT *pPrt = &pAC->GIni.GP[Port];
+       unsigned long Flags;
+       int err = 0;
+       int reg = data->reg_num & 0x1f;
+       SK_U16 val = data->val_in;
+
+       if (!netif_running(dev))
+               return -ENODEV; /* Phy still in reset */
+
+       spin_lock_irqsave(&pAC->SlowPathLock, Flags);
+       switch(cmd) {
+       case SIOCGMIIPHY:
+               data->phy_id = pPrt->PhyAddr;
+
+               /* fallthru */
+       case SIOCGMIIREG:
+               if (pAC->GIni.GIGenesis)
+                       SkXmPhyRead(pAC, IoC, Port, reg, &val);
+               else
+                       SkGmPhyRead(pAC, IoC, Port, reg, &val);
+
+               data->val_out = val;
+               break;
+
+       case SIOCSMIIREG:
+               if (!capable(CAP_NET_ADMIN))
+                       err = -EPERM;
+
+               else if (pAC->GIni.GIGenesis)
+                       SkXmPhyWrite(pAC, IoC, Port, reg, val);
+               else
+                       SkGmPhyWrite(pAC, IoC, Port, reg, val);
+               break;
+       default:
+               err = -EOPNOTSUPP;
+       }
+        spin_unlock_irqrestore(&pAC->SlowPathLock, Flags);
+       return err;
+}
+
+
+/*****************************************************************************
+ *
+ *     SkGeIoctl - IO-control function
+ *
+ * Description:
+ *     This function is called if an ioctl is issued on the device.
+ *     There are three subfunction for reading, writing and test-writing
+ *     the private MIB data structure (useful for SysKonnect-internal tools).
+ *
+ * Returns:
+ *     0, if everything is ok
+ *     !=0, on error
+ */
+static int SkGeIoctl(struct SK_NET_DEVICE *dev, struct ifreq *rq, int cmd)
+{
+DEV_NET                *pNet;
+SK_AC          *pAC;
+void           *pMemBuf;
+struct pci_dev  *pdev = NULL;
+SK_GE_IOCTL    Ioctl;
+unsigned int   Err = 0;
+int            Size = 0;
+int             Ret = 0;
+unsigned int   Length = 0;
+int            HeaderLength = sizeof(SK_U32) + sizeof(SK_U32);
+
+       SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY,
+               ("SkGeIoctl starts now...\n"));
+
+       pNet = netdev_priv(dev);
+       pAC = pNet->pAC;
+       
+       if (cmd == SIOCGMIIPHY || cmd == SIOCSMIIREG || cmd == SIOCGMIIREG)
+           return SkGeMiiIoctl(dev, if_mii(rq), cmd);
+
+       if(copy_from_user(&Ioctl, rq->ifr_data, sizeof(SK_GE_IOCTL))) {
+               return -EFAULT;
+       }
+
+       switch(cmd) {
+       case SK_IOCTL_SETMIB:
+       case SK_IOCTL_PRESETMIB:
+               if (!capable(CAP_NET_ADMIN)) return -EPERM;
+       case SK_IOCTL_GETMIB:
+               if(copy_from_user(&pAC->PnmiStruct, Ioctl.pData,
+                       Ioctl.Len<sizeof(pAC->PnmiStruct)?
+                       Ioctl.Len : sizeof(pAC->PnmiStruct))) {
+                       return -EFAULT;
+               }
+               Size = SkGeIocMib(pNet, Ioctl.Len, cmd);
+               if(copy_to_user(Ioctl.pData, &pAC->PnmiStruct,
+                       Ioctl.Len<Size? Ioctl.Len : Size)) {
+                       return -EFAULT;
+               }
+               Ioctl.Len = Size;
+               if(copy_to_user(rq->ifr_data, &Ioctl, sizeof(SK_GE_IOCTL))) {
+                       return -EFAULT;
+               }
+               break;
+       case SK_IOCTL_GEN:
+               if (Ioctl.Len < (sizeof(pAC->PnmiStruct) + HeaderLength)) {
+                       Length = Ioctl.Len;
+               } else {
+                       Length = sizeof(pAC->PnmiStruct) + HeaderLength;
+               }
+               if (NULL == (pMemBuf = kmalloc(Length, GFP_KERNEL))) {
+                       return -ENOMEM;
+               }
+               if(copy_from_user(pMemBuf, Ioctl.pData, Length)) {
+                       Err = -EFAULT;
+                       goto fault_gen;
+               }
+               if ((Ret = SkPnmiGenIoctl(pAC, pAC->IoBase, pMemBuf, &Length, 0)) < 0) {
+                       Err = -EFAULT;
+                       goto fault_gen;
+               }
+               if(copy_to_user(Ioctl.pData, pMemBuf, Length) ) {
+                       Err = -EFAULT;
+                       goto fault_gen;
+               }
+               Ioctl.Len = Length;
+               if(copy_to_user(rq->ifr_data, &Ioctl, sizeof(SK_GE_IOCTL))) {
+                       Err = -EFAULT;
+                       goto fault_gen;
+               }
+fault_gen:
+               kfree(pMemBuf); /* cleanup everything */
+               break;
+#ifdef SK_DIAG_SUPPORT
+       case SK_IOCTL_DIAG:
+               if (!capable(CAP_NET_ADMIN)) return -EPERM;
+               if (Ioctl.Len < (sizeof(pAC->PnmiStruct) + HeaderLength)) {
+                       Length = Ioctl.Len;
+               } else {
+                       Length = sizeof(pAC->PnmiStruct) + HeaderLength;
+               }
+               if (NULL == (pMemBuf = kmalloc(Length, GFP_KERNEL))) {
+                       return -ENOMEM;
+               }
+               if(copy_from_user(pMemBuf, Ioctl.pData, Length)) {
+                       Err = -EFAULT;
+                       goto fault_diag;
+               }
+               pdev = pAC->PciDev;
+               Length = 3 * sizeof(SK_U32);  /* Error, Bus and Device */
+               /* 
+               ** While coding this new IOCTL interface, only a few lines of code
+               ** are to to be added. Therefore no dedicated function has been 
+               ** added. If more functionality is added, a separate function 
+               ** should be used...
+               */
+               * ((SK_U32 *)pMemBuf) = 0;
+               * ((SK_U32 *)pMemBuf + 1) = pdev->bus->number;
+               * ((SK_U32 *)pMemBuf + 2) = ParseDeviceNbrFromSlotName(pci_name(pdev));
+               if(copy_to_user(Ioctl.pData, pMemBuf, Length) ) {
+                       Err = -EFAULT;
+                       goto fault_diag;
+               }
+               Ioctl.Len = Length;
+               if(copy_to_user(rq->ifr_data, &Ioctl, sizeof(SK_GE_IOCTL))) {
+                       Err = -EFAULT;
+                       goto fault_diag;
+               }
+fault_diag:
+               kfree(pMemBuf); /* cleanup everything */
+               break;
+#endif
+       default:
+               Err = -EOPNOTSUPP;
+       }
+
+       return(Err);
+
+} /* SkGeIoctl */
+
+
+/*****************************************************************************
+ *
+ *     SkGeIocMib - handle a GetMib, SetMib- or PresetMib-ioctl message
+ *
+ * Description:
+ *     This function reads/writes the MIB data using PNMI (Private Network
+ *     Management Interface).
+ *     The destination for the data must be provided with the
+ *     ioctl call and is given to the driver in the form of
+ *     a user space address.
+ *     Copying from the user-provided data area into kernel messages
+ *     and back is done by copy_from_user and copy_to_user calls in
+ *     SkGeIoctl.
+ *
+ * Returns:
+ *     returned size from PNMI call
+ */
+static int SkGeIocMib(
+DEV_NET                *pNet,  /* pointer to the adapter context */
+unsigned int   Size,   /* length of ioctl data */
+int            mode)   /* flag for set/preset */
+{
+unsigned long  Flags;  /* for spin lock */
+SK_AC          *pAC;
+
+       SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY,
+               ("SkGeIocMib starts now...\n"));
+       pAC = pNet->pAC;
+       /* access MIB */
+       spin_lock_irqsave(&pAC->SlowPathLock, Flags);
+       switch(mode) {
+       case SK_IOCTL_GETMIB:
+               SkPnmiGetStruct(pAC, pAC->IoBase, &pAC->PnmiStruct, &Size,
+                       pNet->NetNr);
+               break;
+       case SK_IOCTL_PRESETMIB:
+               SkPnmiPreSetStruct(pAC, pAC->IoBase, &pAC->PnmiStruct, &Size,
+                       pNet->NetNr);
+               break;
+       case SK_IOCTL_SETMIB:
+               SkPnmiSetStruct(pAC, pAC->IoBase, &pAC->PnmiStruct, &Size,
+                       pNet->NetNr);
+               break;
+       default:
+               break;
+       }
+       spin_unlock_irqrestore(&pAC->SlowPathLock, Flags);
+       SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY,
+               ("MIB data access succeeded\n"));
+       return (Size);
+} /* SkGeIocMib */
+
+
+/*****************************************************************************
+ *
+ *     GetConfiguration - read configuration information
+ *
+ * Description:
+ *     This function reads per-adapter configuration information from
+ *     the options provided on the command line.
+ *
+ * Returns:
+ *     none
+ */
+static void GetConfiguration(
+SK_AC  *pAC)   /* pointer to the adapter context structure */
+{
+SK_I32 Port;           /* preferred port */
+SK_BOOL        AutoSet;
+SK_BOOL DupSet;
+int    LinkSpeed          = SK_LSPEED_AUTO;    /* Link speed */
+int    AutoNeg            = 1;                 /* autoneg off (0) or on (1) */
+int    DuplexCap          = 0;                 /* 0=both,1=full,2=half */
+int    FlowCtrl           = SK_FLOW_MODE_SYM_OR_REM;   /* FlowControl  */
+int    MSMode             = SK_MS_MODE_AUTO;   /* master/slave mode    */
+
+SK_BOOL IsConTypeDefined   = SK_TRUE;
+SK_BOOL IsLinkSpeedDefined = SK_TRUE;
+SK_BOOL IsFlowCtrlDefined  = SK_TRUE;
+SK_BOOL IsRoleDefined      = SK_TRUE;
+SK_BOOL IsModeDefined      = SK_TRUE;
+/*
+ *     The two parameters AutoNeg. and DuplexCap. map to one configuration
+ *     parameter. The mapping is described by this table:
+ *     DuplexCap ->    |       both    |       full    |       half    |
+ *     AutoNeg         |               |               |               |
+ *     -----------------------------------------------------------------
+ *     Off             |    illegal    |       Full    |       Half    |
+ *     -----------------------------------------------------------------
+ *     On              |   AutoBoth    |   AutoFull    |   AutoHalf    |
+ *     -----------------------------------------------------------------
+ *     Sense           |   AutoSense   |   AutoSense   |   AutoSense   |
+ */
+int    Capabilities[3][3] =
+               { {                -1, SK_LMODE_FULL     , SK_LMODE_HALF     },
+                 {SK_LMODE_AUTOBOTH , SK_LMODE_AUTOFULL , SK_LMODE_AUTOHALF },
+                 {SK_LMODE_AUTOSENSE, SK_LMODE_AUTOSENSE, SK_LMODE_AUTOSENSE} };
+
+#define DC_BOTH        0
+#define DC_FULL 1
+#define DC_HALF 2
+#define AN_OFF 0
+#define AN_ON  1
+#define AN_SENS        2
+#define M_CurrPort pAC->GIni.GP[Port]
+
+
+       /*
+       ** Set the default values first for both ports!
+       */
+       for (Port = 0; Port < SK_MAX_MACS; Port++) {
+               M_CurrPort.PLinkModeConf = Capabilities[AN_ON][DC_BOTH];
+               M_CurrPort.PFlowCtrlMode = SK_FLOW_MODE_SYM_OR_REM;
+               M_CurrPort.PMSMode       = SK_MS_MODE_AUTO;
+               M_CurrPort.PLinkSpeed    = SK_LSPEED_AUTO;
+       }
+
+       /*
+       ** Check merged parameter ConType. If it has not been used,
+       ** verify any other parameter (e.g. AutoNeg) and use default values. 
+       **
+       ** Stating both ConType and other lowlevel link parameters is also
+       ** possible. If this is the case, the passed ConType-parameter is 
+       ** overwritten by the lowlevel link parameter.
+       **
+       ** The following settings are used for a merged ConType-parameter:
+       **
+       ** ConType   DupCap   AutoNeg   FlowCtrl      Role      Speed
+       ** -------   ------   -------   --------   ----------   -----
+       **  Auto      Both      On      SymOrRem      Auto       Auto
+       **  100FD     Full      Off       None      <ignored>    100
+       **  100HD     Half      Off       None      <ignored>    100
+       **  10FD      Full      Off       None      <ignored>    10
+       **  10HD      Half      Off       None      <ignored>    10
+       ** 
+       ** This ConType parameter is used for all ports of the adapter!
+       */
+        if ( (ConType != NULL)                && 
+            (pAC->Index < SK_MAX_CARD_PARAM) &&
+            (ConType[pAC->Index] != NULL) ) {
+
+                       /* Check chipset family */
+                       if ((!pAC->ChipsetType) && 
+                               (strcmp(ConType[pAC->Index],"Auto")!=0) &&
+                               (strcmp(ConType[pAC->Index],"")!=0)) {
+                               /* Set the speed parameter back */
+                                       printk("sk98lin: Illegal value \"%s\" " 
+                                                       "for ConType."
+                                                       " Using Auto.\n", 
+                                                       ConType[pAC->Index]);
+
+                                       sprintf(ConType[pAC->Index], "Auto");   
+                       }
+
+                               if (strcmp(ConType[pAC->Index],"")==0) {
+                       IsConTypeDefined = SK_FALSE; /* No ConType defined */
+                               } else if (strcmp(ConType[pAC->Index],"Auto")==0) {
+                   for (Port = 0; Port < SK_MAX_MACS; Port++) {
+                       M_CurrPort.PLinkModeConf = Capabilities[AN_ON][DC_BOTH];
+                       M_CurrPort.PFlowCtrlMode = SK_FLOW_MODE_SYM_OR_REM;
+                       M_CurrPort.PMSMode       = SK_MS_MODE_AUTO;
+                       M_CurrPort.PLinkSpeed    = SK_LSPEED_AUTO;
+                   }
+                } else if (strcmp(ConType[pAC->Index],"100FD")==0) {
+                   for (Port = 0; Port < SK_MAX_MACS; Port++) {
+                       M_CurrPort.PLinkModeConf = Capabilities[AN_OFF][DC_FULL];
+                       M_CurrPort.PFlowCtrlMode = SK_FLOW_MODE_NONE;
+                       M_CurrPort.PMSMode       = SK_MS_MODE_AUTO;
+                       M_CurrPort.PLinkSpeed    = SK_LSPEED_100MBPS;
+                   }
+                } else if (strcmp(ConType[pAC->Index],"100HD")==0) {
+                   for (Port = 0; Port < SK_MAX_MACS; Port++) {
+                       M_CurrPort.PLinkModeConf = Capabilities[AN_OFF][DC_HALF];
+                       M_CurrPort.PFlowCtrlMode = SK_FLOW_MODE_NONE;
+                       M_CurrPort.PMSMode       = SK_MS_MODE_AUTO;
+                       M_CurrPort.PLinkSpeed    = SK_LSPEED_100MBPS;
+                   }
+                } else if (strcmp(ConType[pAC->Index],"10FD")==0) {
+                   for (Port = 0; Port < SK_MAX_MACS; Port++) {
+                       M_CurrPort.PLinkModeConf = Capabilities[AN_OFF][DC_FULL];
+                       M_CurrPort.PFlowCtrlMode = SK_FLOW_MODE_NONE;
+                       M_CurrPort.PMSMode       = SK_MS_MODE_AUTO;
+                       M_CurrPort.PLinkSpeed    = SK_LSPEED_10MBPS;
+                   }
+                } else if (strcmp(ConType[pAC->Index],"10HD")==0) {
+                   for (Port = 0; Port < SK_MAX_MACS; Port++) {
+                       M_CurrPort.PLinkModeConf = Capabilities[AN_OFF][DC_HALF];
+                       M_CurrPort.PFlowCtrlMode = SK_FLOW_MODE_NONE;
+                       M_CurrPort.PMSMode       = SK_MS_MODE_AUTO;
+                       M_CurrPort.PLinkSpeed    = SK_LSPEED_10MBPS;
+                   }
+                } else { 
+                   printk("sk98lin: Illegal value \"%s\" for ConType\n", 
+                       ConType[pAC->Index]);
+                   IsConTypeDefined = SK_FALSE; /* Wrong ConType defined */
+               }
+        } else {
+           IsConTypeDefined = SK_FALSE; /* No ConType defined */
+       }
+
+       /*
+       ** Parse any parameter settings for port A:
+       ** a) any LinkSpeed stated?
+       */
+       if (Speed_A != NULL && pAC->Index<SK_MAX_CARD_PARAM &&
+               Speed_A[pAC->Index] != NULL) {
+               if (strcmp(Speed_A[pAC->Index],"")==0) {
+                   IsLinkSpeedDefined = SK_FALSE;
+               } else if (strcmp(Speed_A[pAC->Index],"Auto")==0) {
+                   LinkSpeed = SK_LSPEED_AUTO;
+               } else if (strcmp(Speed_A[pAC->Index],"10")==0) {
+                   LinkSpeed = SK_LSPEED_10MBPS;
+               } else if (strcmp(Speed_A[pAC->Index],"100")==0) {
+                   LinkSpeed = SK_LSPEED_100MBPS;
+               } else if (strcmp(Speed_A[pAC->Index],"1000")==0) {
+                   LinkSpeed = SK_LSPEED_1000MBPS;
+               } else {
+                   printk("sk98lin: Illegal value \"%s\" for Speed_A\n",
+                       Speed_A[pAC->Index]);
+                   IsLinkSpeedDefined = SK_FALSE;
+               }
+       } else {
+           IsLinkSpeedDefined = SK_FALSE;
+       }
+
+       /* 
+       ** Check speed parameter: 
+       **    Only copper type adapter and GE V2 cards 
+       */
+       if (((!pAC->ChipsetType) || (pAC->GIni.GICopperType != SK_TRUE)) &&
+               ((LinkSpeed != SK_LSPEED_AUTO) &&
+               (LinkSpeed != SK_LSPEED_1000MBPS))) {
+               printk("sk98lin: Illegal value for Speed_A. "
+                       "Not a copper card or GE V2 card\n    Using "
+                       "speed 1000\n");
+               LinkSpeed = SK_LSPEED_1000MBPS;
+       }
+       
+       /*      
+       ** Decide whether to set new config value if somethig valid has
+       ** been received.
+       */
+       if (IsLinkSpeedDefined) {
+               pAC->GIni.GP[0].PLinkSpeed = LinkSpeed;
+       } 
+
+       /* 
+       ** b) Any Autonegotiation and DuplexCapabilities set?
+       **    Please note that both belong together...
+       */
+       AutoNeg = AN_ON; /* tschilling: Default: Autonegotiation on! */
+       AutoSet = SK_FALSE;
+       if (AutoNeg_A != NULL && pAC->Index<SK_MAX_CARD_PARAM &&
+               AutoNeg_A[pAC->Index] != NULL) {
+               AutoSet = SK_TRUE;
+               if (strcmp(AutoNeg_A[pAC->Index],"")==0) {
+                   AutoSet = SK_FALSE;
+               } else if (strcmp(AutoNeg_A[pAC->Index],"On")==0) {
+                   AutoNeg = AN_ON;
+               } else if (strcmp(AutoNeg_A[pAC->Index],"Off")==0) {
+                   AutoNeg = AN_OFF;
+               } else if (strcmp(AutoNeg_A[pAC->Index],"Sense")==0) {
+                   AutoNeg = AN_SENS;
+               } else {
+                   printk("sk98lin: Illegal value \"%s\" for AutoNeg_A\n",
+                       AutoNeg_A[pAC->Index]);
+               }
+       }
+
+       DuplexCap = DC_BOTH;
+       DupSet    = SK_FALSE;
+       if (DupCap_A != NULL && pAC->Index<SK_MAX_CARD_PARAM &&
+               DupCap_A[pAC->Index] != NULL) {
+               DupSet = SK_TRUE;
+               if (strcmp(DupCap_A[pAC->Index],"")==0) {
+                   DupSet = SK_FALSE;
+               } else if (strcmp(DupCap_A[pAC->Index],"Both")==0) {
+                   DuplexCap = DC_BOTH;
+               } else if (strcmp(DupCap_A[pAC->Index],"Full")==0) {
+                   DuplexCap = DC_FULL;
+               } else if (strcmp(DupCap_A[pAC->Index],"Half")==0) {
+                   DuplexCap = DC_HALF;
+               } else {
+                   printk("sk98lin: Illegal value \"%s\" for DupCap_A\n",
+                       DupCap_A[pAC->Index]);
+               }
+       }
+
+       /* 
+       ** Check for illegal combinations 
+       */
+       if ((LinkSpeed == SK_LSPEED_1000MBPS) &&
+               ((DuplexCap == SK_LMODE_STAT_AUTOHALF) ||
+               (DuplexCap == SK_LMODE_STAT_HALF)) &&
+               (pAC->ChipsetType)) {
+                   printk("sk98lin: Half Duplex not possible with Gigabit speed!\n"
+                                       "    Using Full Duplex.\n");
+                               DuplexCap = DC_FULL;
+       }
+
+       if ( AutoSet && AutoNeg==AN_SENS && DupSet) {
+               printk("sk98lin, Port A: DuplexCapabilities"
+                       " ignored using Sense mode\n");
+       }
+
+       if (AutoSet && AutoNeg==AN_OFF && DupSet && DuplexCap==DC_BOTH){
+               printk("sk98lin: Port A: Illegal combination"
+                       " of values AutoNeg. and DuplexCap.\n    Using "
+                       "Full Duplex\n");
+               DuplexCap = DC_FULL;
+       }
+
+       if (AutoSet && AutoNeg==AN_OFF && !DupSet) {
+               DuplexCap = DC_FULL;
+       }
+       
+       if (!AutoSet && DupSet) {
+               printk("sk98lin: Port A: Duplex setting not"
+                       " possible in\n    default AutoNegotiation mode"
+                       " (Sense).\n    Using AutoNegotiation On\n");
+               AutoNeg = AN_ON;
+       }
+       
+       /* 
+       ** set the desired mode 
+       */
+       if (AutoSet || DupSet) {
+           pAC->GIni.GP[0].PLinkModeConf = Capabilities[AutoNeg][DuplexCap];
+       }
+       
+       /* 
+       ** c) Any Flowcontrol-parameter set?
+       */
+       if (FlowCtrl_A != NULL && pAC->Index<SK_MAX_CARD_PARAM &&
+               FlowCtrl_A[pAC->Index] != NULL) {
+               if (strcmp(FlowCtrl_A[pAC->Index],"") == 0) {
+                   IsFlowCtrlDefined = SK_FALSE;
+               } else if (strcmp(FlowCtrl_A[pAC->Index],"SymOrRem") == 0) {
+                   FlowCtrl = SK_FLOW_MODE_SYM_OR_REM;
+               } else if (strcmp(FlowCtrl_A[pAC->Index],"Sym")==0) {
+                   FlowCtrl = SK_FLOW_MODE_SYMMETRIC;
+               } else if (strcmp(FlowCtrl_A[pAC->Index],"LocSend")==0) {
+                   FlowCtrl = SK_FLOW_MODE_LOC_SEND;
+               } else if (strcmp(FlowCtrl_A[pAC->Index],"None")==0) {
+                   FlowCtrl = SK_FLOW_MODE_NONE;
+               } else {
+                   printk("sk98lin: Illegal value \"%s\" for FlowCtrl_A\n",
+                        FlowCtrl_A[pAC->Index]);
+                   IsFlowCtrlDefined = SK_FALSE;
+               }
+       } else {
+          IsFlowCtrlDefined = SK_FALSE;
+       }
+
+       if (IsFlowCtrlDefined) {
+           if ((AutoNeg == AN_OFF) && (FlowCtrl != SK_FLOW_MODE_NONE)) {
+               printk("sk98lin: Port A: FlowControl"
+                       " impossible without AutoNegotiation,"
+                       " disabled\n");
+               FlowCtrl = SK_FLOW_MODE_NONE;
+           }
+           pAC->GIni.GP[0].PFlowCtrlMode = FlowCtrl;
+       }
+
+       /*
+       ** d) What is with the RoleParameter?
+       */
+       if (Role_A != NULL && pAC->Index<SK_MAX_CARD_PARAM &&
+               Role_A[pAC->Index] != NULL) {
+               if (strcmp(Role_A[pAC->Index],"")==0) {
+                  IsRoleDefined = SK_FALSE;
+               } else if (strcmp(Role_A[pAC->Index],"Auto")==0) {
+                   MSMode = SK_MS_MODE_AUTO;
+               } else if (strcmp(Role_A[pAC->Index],"Master")==0) {
+                   MSMode = SK_MS_MODE_MASTER;
+               } else if (strcmp(Role_A[pAC->Index],"Slave")==0) {
+                   MSMode = SK_MS_MODE_SLAVE;
+               } else {
+                   printk("sk98lin: Illegal value \"%s\" for Role_A\n",
+                       Role_A[pAC->Index]);
+                   IsRoleDefined = SK_FALSE;
+               }
+       } else {
+          IsRoleDefined = SK_FALSE;
+       }
+
+       if (IsRoleDefined == SK_TRUE) {
+           pAC->GIni.GP[0].PMSMode = MSMode;
+       }
+       
+
+       
+       /* 
+       ** Parse any parameter settings for port B:
+       ** a) any LinkSpeed stated?
+       */
+       IsConTypeDefined   = SK_TRUE;
+       IsLinkSpeedDefined = SK_TRUE;
+       IsFlowCtrlDefined  = SK_TRUE;
+       IsModeDefined      = SK_TRUE;
+
+       if (Speed_B != NULL && pAC->Index<SK_MAX_CARD_PARAM &&
+               Speed_B[pAC->Index] != NULL) {
+               if (strcmp(Speed_B[pAC->Index],"")==0) {
+                   IsLinkSpeedDefined = SK_FALSE;
+               } else if (strcmp(Speed_B[pAC->Index],"Auto")==0) {
+                   LinkSpeed = SK_LSPEED_AUTO;
+               } else if (strcmp(Speed_B[pAC->Index],"10")==0) {
+                   LinkSpeed = SK_LSPEED_10MBPS;
+               } else if (strcmp(Speed_B[pAC->Index],"100")==0) {
+                   LinkSpeed = SK_LSPEED_100MBPS;
+               } else if (strcmp(Speed_B[pAC->Index],"1000")==0) {
+                   LinkSpeed = SK_LSPEED_1000MBPS;
+               } else {
+                   printk("sk98lin: Illegal value \"%s\" for Speed_B\n",
+                       Speed_B[pAC->Index]);
+                   IsLinkSpeedDefined = SK_FALSE;
+               }
+       } else {
+           IsLinkSpeedDefined = SK_FALSE;
+       }
+
+       /* 
+       ** Check speed parameter:
+       **    Only copper type adapter and GE V2 cards 
+       */
+       if (((!pAC->ChipsetType) || (pAC->GIni.GICopperType != SK_TRUE)) &&
+               ((LinkSpeed != SK_LSPEED_AUTO) &&
+               (LinkSpeed != SK_LSPEED_1000MBPS))) {
+               printk("sk98lin: Illegal value for Speed_B. "
+                       "Not a copper card or GE V2 card\n    Using "
+                       "speed 1000\n");
+               LinkSpeed = SK_LSPEED_1000MBPS;
+       }
+
+       /*      
+       ** Decide whether to set new config value if somethig valid has
+       ** been received.
+       */
+        if (IsLinkSpeedDefined) {
+           pAC->GIni.GP[1].PLinkSpeed = LinkSpeed;
+       }
+
+       /* 
+       ** b) Any Autonegotiation and DuplexCapabilities set?
+       **    Please note that both belong together...
+       */
+       AutoNeg = AN_SENS; /* default: do auto Sense */
+       AutoSet = SK_FALSE;
+       if (AutoNeg_B != NULL && pAC->Index<SK_MAX_CARD_PARAM &&
+               AutoNeg_B[pAC->Index] != NULL) {
+               AutoSet = SK_TRUE;
+               if (strcmp(AutoNeg_B[pAC->Index],"")==0) {
+                   AutoSet = SK_FALSE;
+               } else if (strcmp(AutoNeg_B[pAC->Index],"On")==0) {
+                   AutoNeg = AN_ON;
+               } else if (strcmp(AutoNeg_B[pAC->Index],"Off")==0) {
+                   AutoNeg = AN_OFF;
+               } else if (strcmp(AutoNeg_B[pAC->Index],"Sense")==0) {
+                   AutoNeg = AN_SENS;
+               } else {
+                   printk("sk98lin: Illegal value \"%s\" for AutoNeg_B\n",
+                       AutoNeg_B[pAC->Index]);
+               }
+       }
+
+       DuplexCap = DC_BOTH;
+       DupSet    = SK_FALSE;
+       if (DupCap_B != NULL && pAC->Index<SK_MAX_CARD_PARAM &&
+               DupCap_B[pAC->Index] != NULL) {
+               DupSet = SK_TRUE;
+               if (strcmp(DupCap_B[pAC->Index],"")==0) {
+                   DupSet = SK_FALSE;
+               } else if (strcmp(DupCap_B[pAC->Index],"Both")==0) {
+                   DuplexCap = DC_BOTH;
+               } else if (strcmp(DupCap_B[pAC->Index],"Full")==0) {
+                   DuplexCap = DC_FULL;
+               } else if (strcmp(DupCap_B[pAC->Index],"Half")==0) {
+                   DuplexCap = DC_HALF;
+               } else {
+                   printk("sk98lin: Illegal value \"%s\" for DupCap_B\n",
+                       DupCap_B[pAC->Index]);
+               }
+       }
+
+       
+       /* 
+       ** Check for illegal combinations 
+       */
+       if ((LinkSpeed == SK_LSPEED_1000MBPS) &&
+               ((DuplexCap == SK_LMODE_STAT_AUTOHALF) ||
+               (DuplexCap == SK_LMODE_STAT_HALF)) &&
+               (pAC->ChipsetType)) {
+                   printk("sk98lin: Half Duplex not possible with Gigabit speed!\n"
+                                       "    Using Full Duplex.\n");
+                               DuplexCap = DC_FULL;
+       }
+
+       if (AutoSet && AutoNeg==AN_SENS && DupSet) {
+               printk("sk98lin, Port B: DuplexCapabilities"
+                       " ignored using Sense mode\n");
+       }
+
+       if (AutoSet && AutoNeg==AN_OFF && DupSet && DuplexCap==DC_BOTH){
+               printk("sk98lin: Port B: Illegal combination"
+                       " of values AutoNeg. and DuplexCap.\n    Using "
+                       "Full Duplex\n");
+               DuplexCap = DC_FULL;
+       }
+
+       if (AutoSet && AutoNeg==AN_OFF && !DupSet) {
+               DuplexCap = DC_FULL;
+       }
+       
+       if (!AutoSet && DupSet) {
+               printk("sk98lin: Port B: Duplex setting not"
+                       " possible in\n    default AutoNegotiation mode"
+                       " (Sense).\n    Using AutoNegotiation On\n");
+               AutoNeg = AN_ON;
+       }
+
+       /* 
+       ** set the desired mode 
+       */
+       if (AutoSet || DupSet) {
+           pAC->GIni.GP[1].PLinkModeConf = Capabilities[AutoNeg][DuplexCap];
+       }
+
+       /*
+       ** c) Any FlowCtrl parameter set?
+       */
+       if (FlowCtrl_B != NULL && pAC->Index<SK_MAX_CARD_PARAM &&
+               FlowCtrl_B[pAC->Index] != NULL) {
+               if (strcmp(FlowCtrl_B[pAC->Index],"") == 0) {
+                   IsFlowCtrlDefined = SK_FALSE;
+               } else if (strcmp(FlowCtrl_B[pAC->Index],"SymOrRem") == 0) {
+                   FlowCtrl = SK_FLOW_MODE_SYM_OR_REM;
+               } else if (strcmp(FlowCtrl_B[pAC->Index],"Sym")==0) {
+                   FlowCtrl = SK_FLOW_MODE_SYMMETRIC;
+               } else if (strcmp(FlowCtrl_B[pAC->Index],"LocSend")==0) {
+                   FlowCtrl = SK_FLOW_MODE_LOC_SEND;
+               } else if (strcmp(FlowCtrl_B[pAC->Index],"None")==0) {
+                   FlowCtrl = SK_FLOW_MODE_NONE;
+               } else {
+                   printk("sk98lin: Illegal value \"%s\" for FlowCtrl_B\n",
+                       FlowCtrl_B[pAC->Index]);
+                   IsFlowCtrlDefined = SK_FALSE;
+               }
+       } else {
+               IsFlowCtrlDefined = SK_FALSE;
+       }
+
+       if (IsFlowCtrlDefined) {
+           if ((AutoNeg == AN_OFF) && (FlowCtrl != SK_FLOW_MODE_NONE)) {
+               printk("sk98lin: Port B: FlowControl"
+                       " impossible without AutoNegotiation,"
+                       " disabled\n");
+               FlowCtrl = SK_FLOW_MODE_NONE;
+           }
+           pAC->GIni.GP[1].PFlowCtrlMode = FlowCtrl;
+       }
+
+       /*
+       ** d) What is the RoleParameter?
+       */
+       if (Role_B != NULL && pAC->Index<SK_MAX_CARD_PARAM &&
+               Role_B[pAC->Index] != NULL) {
+               if (strcmp(Role_B[pAC->Index],"")==0) {
+                   IsRoleDefined = SK_FALSE;
+               } else if (strcmp(Role_B[pAC->Index],"Auto")==0) {
+                   MSMode = SK_MS_MODE_AUTO;
+               } else if (strcmp(Role_B[pAC->Index],"Master")==0) {
+                   MSMode = SK_MS_MODE_MASTER;
+               } else if (strcmp(Role_B[pAC->Index],"Slave")==0) {
+                   MSMode = SK_MS_MODE_SLAVE;
+               } else {
+                   printk("sk98lin: Illegal value \"%s\" for Role_B\n",
+                       Role_B[pAC->Index]);
+                   IsRoleDefined = SK_FALSE;
+               }
+       } else {
+           IsRoleDefined = SK_FALSE;
+       }
+
+       if (IsRoleDefined) {
+           pAC->GIni.GP[1].PMSMode = MSMode;
+       }
+       
+       /*
+       ** Evaluate settings for both ports
+       */
+       pAC->ActivePort = 0;
+       if (PrefPort != NULL && pAC->Index<SK_MAX_CARD_PARAM &&
+               PrefPort[pAC->Index] != NULL) {
+               if (strcmp(PrefPort[pAC->Index],"") == 0) { /* Auto */
+                       pAC->ActivePort             =  0;
+                       pAC->Rlmt.Net[0].Preference = -1; /* auto */
+                       pAC->Rlmt.Net[0].PrefPort   =  0;
+               } else if (strcmp(PrefPort[pAC->Index],"A") == 0) {
+                       /*
+                       ** do not set ActivePort here, thus a port
+                       ** switch is issued after net up.
+                       */
+                       Port                        = 0;
+                       pAC->Rlmt.Net[0].Preference = Port;
+                       pAC->Rlmt.Net[0].PrefPort   = Port;
+               } else if (strcmp(PrefPort[pAC->Index],"B") == 0) {
+                       /*
+                       ** do not set ActivePort here, thus a port
+                       ** switch is issued after net up.
+                       */
+                       if (pAC->GIni.GIMacsFound == 1) {
+                               printk("sk98lin: Illegal value \"B\" for PrefPort.\n"
+                                       "      Port B not available on single port adapters.\n");
+
+                               pAC->ActivePort             =  0;
+                               pAC->Rlmt.Net[0].Preference = -1; /* auto */
+                               pAC->Rlmt.Net[0].PrefPort   =  0;
+                       } else {
+                               Port                        = 1;
+                               pAC->Rlmt.Net[0].Preference = Port;
+                               pAC->Rlmt.Net[0].PrefPort   = Port;
+                       }
+               } else {
+                   printk("sk98lin: Illegal value \"%s\" for PrefPort\n",
+                       PrefPort[pAC->Index]);
+               }
+       }
+
+       pAC->RlmtNets = 1;
+
+       if (RlmtMode != NULL && pAC->Index<SK_MAX_CARD_PARAM &&
+               RlmtMode[pAC->Index] != NULL) {
+               if (strcmp(RlmtMode[pAC->Index], "") == 0) {
+                       pAC->RlmtMode = 0;
+               } else if (strcmp(RlmtMode[pAC->Index], "CheckLinkState") == 0) {
+                       pAC->RlmtMode = SK_RLMT_CHECK_LINK;
+               } else if (strcmp(RlmtMode[pAC->Index], "CheckLocalPort") == 0) {
+                       pAC->RlmtMode = SK_RLMT_CHECK_LINK |
+                                       SK_RLMT_CHECK_LOC_LINK;
+               } else if (strcmp(RlmtMode[pAC->Index], "CheckSeg") == 0) {
+                       pAC->RlmtMode = SK_RLMT_CHECK_LINK     |
+                                       SK_RLMT_CHECK_LOC_LINK |
+                                       SK_RLMT_CHECK_SEG;
+               } else if ((strcmp(RlmtMode[pAC->Index], "DualNet") == 0) &&
+                       (pAC->GIni.GIMacsFound == 2)) {
+                       pAC->RlmtMode = SK_RLMT_CHECK_LINK;
+                       pAC->RlmtNets = 2;
+               } else {
+                   printk("sk98lin: Illegal value \"%s\" for"
+                       " RlmtMode, using default\n", 
+                       RlmtMode[pAC->Index]);
+                       pAC->RlmtMode = 0;
+               }
+       } else {
+               pAC->RlmtMode = 0;
+       }
+       
+       /*
+       ** Check the interrupt moderation parameters
+       */
+       if (Moderation[pAC->Index] != NULL) {
+               if (strcmp(Moderation[pAC->Index], "") == 0) {
+                       pAC->DynIrqModInfo.IntModTypeSelect = C_INT_MOD_NONE;
+               } else if (strcmp(Moderation[pAC->Index], "Static") == 0) {
+                       pAC->DynIrqModInfo.IntModTypeSelect = C_INT_MOD_STATIC;
+               } else if (strcmp(Moderation[pAC->Index], "Dynamic") == 0) {
+                       pAC->DynIrqModInfo.IntModTypeSelect = C_INT_MOD_DYNAMIC;
+               } else if (strcmp(Moderation[pAC->Index], "None") == 0) {
+                       pAC->DynIrqModInfo.IntModTypeSelect = C_INT_MOD_NONE;
+               } else {
+                       printk("sk98lin: Illegal value \"%s\" for Moderation.\n"
+                               "      Disable interrupt moderation.\n",
+                               Moderation[pAC->Index]);
+                       pAC->DynIrqModInfo.IntModTypeSelect = C_INT_MOD_NONE;
+               }
+       } else {
+               pAC->DynIrqModInfo.IntModTypeSelect = C_INT_MOD_NONE;
+       }
+
+       if (Stats[pAC->Index] != NULL) {
+               if (strcmp(Stats[pAC->Index], "Yes") == 0) {
+                       pAC->DynIrqModInfo.DisplayStats = SK_TRUE;
+               } else {
+                       pAC->DynIrqModInfo.DisplayStats = SK_FALSE;
+               }
+       } else {
+               pAC->DynIrqModInfo.DisplayStats = SK_FALSE;
+       }
+
+       if (ModerationMask[pAC->Index] != NULL) {
+               if (strcmp(ModerationMask[pAC->Index], "Rx") == 0) {
+                       pAC->DynIrqModInfo.MaskIrqModeration = IRQ_MASK_RX_ONLY;
+               } else if (strcmp(ModerationMask[pAC->Index], "Tx") == 0) {
+                       pAC->DynIrqModInfo.MaskIrqModeration = IRQ_MASK_TX_ONLY;
+               } else if (strcmp(ModerationMask[pAC->Index], "Sp") == 0) {
+                       pAC->DynIrqModInfo.MaskIrqModeration = IRQ_MASK_SP_ONLY;
+               } else if (strcmp(ModerationMask[pAC->Index], "RxSp") == 0) {
+                       pAC->DynIrqModInfo.MaskIrqModeration = IRQ_MASK_SP_RX;
+               } else if (strcmp(ModerationMask[pAC->Index], "SpRx") == 0) {
+                       pAC->DynIrqModInfo.MaskIrqModeration = IRQ_MASK_SP_RX;
+               } else if (strcmp(ModerationMask[pAC->Index], "RxTx") == 0) {
+                       pAC->DynIrqModInfo.MaskIrqModeration = IRQ_MASK_TX_RX;
+               } else if (strcmp(ModerationMask[pAC->Index], "TxRx") == 0) {
+                       pAC->DynIrqModInfo.MaskIrqModeration = IRQ_MASK_TX_RX;
+               } else if (strcmp(ModerationMask[pAC->Index], "TxSp") == 0) {
+                       pAC->DynIrqModInfo.MaskIrqModeration = IRQ_MASK_SP_TX;
+               } else if (strcmp(ModerationMask[pAC->Index], "SpTx") == 0) {
+                       pAC->DynIrqModInfo.MaskIrqModeration = IRQ_MASK_SP_TX;
+               } else if (strcmp(ModerationMask[pAC->Index], "RxTxSp") == 0) {
+                       pAC->DynIrqModInfo.MaskIrqModeration = IRQ_MASK_RX_TX_SP;
+               } else if (strcmp(ModerationMask[pAC->Index], "RxSpTx") == 0) {
+                       pAC->DynIrqModInfo.MaskIrqModeration = IRQ_MASK_RX_TX_SP;
+               } else if (strcmp(ModerationMask[pAC->Index], "TxRxSp") == 0) {
+                       pAC->DynIrqModInfo.MaskIrqModeration = IRQ_MASK_RX_TX_SP;
+               } else if (strcmp(ModerationMask[pAC->Index], "TxSpRx") == 0) {
+                       pAC->DynIrqModInfo.MaskIrqModeration = IRQ_MASK_RX_TX_SP;
+               } else if (strcmp(ModerationMask[pAC->Index], "SpTxRx") == 0) {
+                       pAC->DynIrqModInfo.MaskIrqModeration = IRQ_MASK_RX_TX_SP;
+               } else if (strcmp(ModerationMask[pAC->Index], "SpRxTx") == 0) {
+                       pAC->DynIrqModInfo.MaskIrqModeration = IRQ_MASK_RX_TX_SP;
+               } else { /* some rubbish */
+                       pAC->DynIrqModInfo.MaskIrqModeration = IRQ_MASK_RX_ONLY;
+               }
+       } else {  /* operator has stated nothing */
+               pAC->DynIrqModInfo.MaskIrqModeration = IRQ_MASK_TX_RX;
+       }
+
+       if (AutoSizing[pAC->Index] != NULL) {
+               if (strcmp(AutoSizing[pAC->Index], "On") == 0) {
+                       pAC->DynIrqModInfo.AutoSizing = SK_FALSE;
+               } else {
+                       pAC->DynIrqModInfo.AutoSizing = SK_FALSE;
+               }
+       } else {  /* operator has stated nothing */
+               pAC->DynIrqModInfo.AutoSizing = SK_FALSE;
+       }
+
+       if (IntsPerSec[pAC->Index] != 0) {
+               if ((IntsPerSec[pAC->Index]< C_INT_MOD_IPS_LOWER_RANGE) || 
+                       (IntsPerSec[pAC->Index] > C_INT_MOD_IPS_UPPER_RANGE)) {
+                       printk("sk98lin: Illegal value \"%d\" for IntsPerSec. (Range: %d - %d)\n"
+                               "      Using default value of %i.\n", 
+                               IntsPerSec[pAC->Index],
+                               C_INT_MOD_IPS_LOWER_RANGE,
+                               C_INT_MOD_IPS_UPPER_RANGE,
+                               C_INTS_PER_SEC_DEFAULT);
+                       pAC->DynIrqModInfo.MaxModIntsPerSec = C_INTS_PER_SEC_DEFAULT;
+               } else {
+                       pAC->DynIrqModInfo.MaxModIntsPerSec = IntsPerSec[pAC->Index];
+               }
+       } else {
+               pAC->DynIrqModInfo.MaxModIntsPerSec = C_INTS_PER_SEC_DEFAULT;
+       }
+
+       /*
+       ** Evaluate upper and lower moderation threshold
+       */
+       pAC->DynIrqModInfo.MaxModIntsPerSecUpperLimit =
+               pAC->DynIrqModInfo.MaxModIntsPerSec +
+               (pAC->DynIrqModInfo.MaxModIntsPerSec / 2);
+
+       pAC->DynIrqModInfo.MaxModIntsPerSecLowerLimit =
+               pAC->DynIrqModInfo.MaxModIntsPerSec -
+               (pAC->DynIrqModInfo.MaxModIntsPerSec / 2);
+
+       pAC->DynIrqModInfo.PrevTimeVal = jiffies;  /* initial value */
+
+
+} /* GetConfiguration */
+
+
+/*****************************************************************************
+ *
+ *     ProductStr - return a adapter identification string from vpd
+ *
+ * Description:
+ *     This function reads the product name string from the vpd area
+ *     and puts it the field pAC->DeviceString.
+ *
+ * Returns: N/A
+ */
+static inline int ProductStr(
+       SK_AC   *pAC,           /* pointer to adapter context */
+       char    *DeviceStr,     /* result string */
+       int      StrLen         /* length of the string */
+)
+{
+char   Keyword[] = VPD_NAME;   /* vpd productname identifier */
+int    ReturnCode;             /* return code from vpd_read */
+unsigned long Flags;
+
+       spin_lock_irqsave(&pAC->SlowPathLock, Flags);
+       ReturnCode = VpdRead(pAC, pAC->IoBase, Keyword, DeviceStr, &StrLen);
+       spin_unlock_irqrestore(&pAC->SlowPathLock, Flags);
+
+       return ReturnCode;
+} /* ProductStr */
+
+/*****************************************************************************
+ *
+ *      StartDrvCleanupTimer - Start timer to check for descriptors which
+ *                             might be placed in descriptor ring, but
+ *                             havent been handled up to now
+ *
+ * Description:
+ *      This function requests a HW-timer fo the Yukon card. The actions to
+ *      perform when this timer expires, are located in the SkDrvEvent().
+ *
+ * Returns: N/A
+ */
+static void
+StartDrvCleanupTimer(SK_AC *pAC) {
+    SK_EVPARA    EventParam;   /* Event struct for timer event */
+
+    SK_MEMSET((char *) &EventParam, 0, sizeof(EventParam));
+    EventParam.Para32[0] = SK_DRV_RX_CLEANUP_TIMER;
+    SkTimerStart(pAC, pAC->IoBase, &pAC->DrvCleanupTimer,
+                 SK_DRV_RX_CLEANUP_TIMER_LENGTH,
+                 SKGE_DRV, SK_DRV_TIMER, EventParam);
+}
+
+/*****************************************************************************
+ *
+ *      StopDrvCleanupTimer - Stop timer to check for descriptors
+ *
+ * Description:
+ *      This function requests a HW-timer fo the Yukon card. The actions to
+ *      perform when this timer expires, are located in the SkDrvEvent().
+ *
+ * Returns: N/A
+ */
+static void
+StopDrvCleanupTimer(SK_AC *pAC) {
+    SkTimerStop(pAC, pAC->IoBase, &pAC->DrvCleanupTimer);
+    SK_MEMSET((char *) &pAC->DrvCleanupTimer, 0, sizeof(SK_TIMER));
+}
+
+/****************************************************************************/
+/* functions for common modules *********************************************/
+/****************************************************************************/
+
+
+/*****************************************************************************
+ *
+ *     SkDrvAllocRlmtMbuf - allocate an RLMT mbuf
+ *
+ * Description:
+ *     This routine returns an RLMT mbuf or NULL. The RLMT Mbuf structure
+ *     is embedded into a socket buff data area.
+ *
+ * Context:
+ *     runtime
+ *
+ * Returns:
+ *     NULL or pointer to Mbuf.
+ */
+SK_MBUF *SkDrvAllocRlmtMbuf(
+SK_AC          *pAC,           /* pointer to adapter context */
+SK_IOC         IoC,            /* the IO-context */
+unsigned       BufferSize)     /* size of the requested buffer */
+{
+SK_MBUF                *pRlmtMbuf;     /* pointer to a new rlmt-mbuf structure */
+struct sk_buff *pMsgBlock;     /* pointer to a new message block */
+
+       pMsgBlock = alloc_skb(BufferSize + sizeof(SK_MBUF), GFP_ATOMIC);
+       if (pMsgBlock == NULL) {
+               return (NULL);
+       }
+       pRlmtMbuf = (SK_MBUF*) pMsgBlock->data;
+       skb_reserve(pMsgBlock, sizeof(SK_MBUF));
+       pRlmtMbuf->pNext = NULL;
+       pRlmtMbuf->pOs = pMsgBlock;
+       pRlmtMbuf->pData = pMsgBlock->data;     /* Data buffer. */
+       pRlmtMbuf->Size = BufferSize;           /* Data buffer size. */
+       pRlmtMbuf->Length = 0;          /* Length of packet (<= Size). */
+       return (pRlmtMbuf);
+
+} /* SkDrvAllocRlmtMbuf */
+
+
+/*****************************************************************************
+ *
+ *     SkDrvFreeRlmtMbuf - free an RLMT mbuf
+ *
+ * Description:
+ *     This routine frees one or more RLMT mbuf(s).
+ *
+ * Context:
+ *     runtime
+ *
+ * Returns:
+ *     Nothing
+ */
+void  SkDrvFreeRlmtMbuf(
+SK_AC          *pAC,           /* pointer to adapter context */
+SK_IOC         IoC,            /* the IO-context */
+SK_MBUF                *pMbuf)         /* size of the requested buffer */
+{
+SK_MBUF                *pFreeMbuf;
+SK_MBUF                *pNextMbuf;
+
+       pFreeMbuf = pMbuf;
+       do {
+               pNextMbuf = pFreeMbuf->pNext;
+               DEV_KFREE_SKB_ANY(pFreeMbuf->pOs);
+               pFreeMbuf = pNextMbuf;
+       } while ( pFreeMbuf != NULL );
+} /* SkDrvFreeRlmtMbuf */
+
+
+/*****************************************************************************
+ *
+ *     SkOsGetTime - provide a time value
+ *
+ * Description:
+ *     This routine provides a time value. The unit is 1/HZ (defined by Linux).
+ *     It is not used for absolute time, but only for time differences.
+ *
+ *
+ * Returns:
+ *     Time value
+ */
+SK_U64 SkOsGetTime(SK_AC *pAC)
+{
+       SK_U64  PrivateJiffies;
+       SkOsGetTimeCurrent(pAC, &PrivateJiffies);
+       return PrivateJiffies;
+} /* SkOsGetTime */
+
+
+/*****************************************************************************
+ *
+ *     SkPciReadCfgDWord - read a 32 bit value from pci config space
+ *
+ * Description:
+ *     This routine reads a 32 bit value from the pci configuration
+ *     space.
+ *
+ * Returns:
+ *     0 - indicate everything worked ok.
+ *     != 0 - error indication
+ */
+int SkPciReadCfgDWord(
+SK_AC *pAC,            /* Adapter Control structure pointer */
+int PciAddr,           /* PCI register address */
+SK_U32 *pVal)          /* pointer to store the read value */
+{
+       pci_read_config_dword(pAC->PciDev, PciAddr, pVal);
+       return(0);
+} /* SkPciReadCfgDWord */
+
+
+/*****************************************************************************
+ *
+ *     SkPciReadCfgWord - read a 16 bit value from pci config space
+ *
+ * Description:
+ *     This routine reads a 16 bit value from the pci configuration
+ *     space.
+ *
+ * Returns:
+ *     0 - indicate everything worked ok.
+ *     != 0 - error indication
+ */
+int SkPciReadCfgWord(
+SK_AC *pAC,    /* Adapter Control structure pointer */
+int PciAddr,           /* PCI register address */
+SK_U16 *pVal)          /* pointer to store the read value */
+{
+       pci_read_config_word(pAC->PciDev, PciAddr, pVal);
+       return(0);
+} /* SkPciReadCfgWord */
+
+
+/*****************************************************************************
+ *
+ *     SkPciReadCfgByte - read a 8 bit value from pci config space
+ *
+ * Description:
+ *     This routine reads a 8 bit value from the pci configuration
+ *     space.
+ *
+ * Returns:
+ *     0 - indicate everything worked ok.
+ *     != 0 - error indication
+ */
+int SkPciReadCfgByte(
+SK_AC *pAC,    /* Adapter Control structure pointer */
+int PciAddr,           /* PCI register address */
+SK_U8 *pVal)           /* pointer to store the read value */
+{
+       pci_read_config_byte(pAC->PciDev, PciAddr, pVal);
+       return(0);
+} /* SkPciReadCfgByte */
+
+
+/*****************************************************************************
+ *
+ *     SkPciWriteCfgWord - write a 16 bit value to pci config space
+ *
+ * Description:
+ *     This routine writes a 16 bit value to the pci configuration
+ *     space. The flag PciConfigUp indicates whether the config space
+ *     is accesible or must be set up first.
+ *
+ * Returns:
+ *     0 - indicate everything worked ok.
+ *     != 0 - error indication
+ */
+int SkPciWriteCfgWord(
+SK_AC *pAC,    /* Adapter Control structure pointer */
+int PciAddr,           /* PCI register address */
+SK_U16 Val)            /* pointer to store the read value */
+{
+       pci_write_config_word(pAC->PciDev, PciAddr, Val);
+       return(0);
+} /* SkPciWriteCfgWord */
+
+
+/*****************************************************************************
+ *
+ *     SkPciWriteCfgWord - write a 8 bit value to pci config space
+ *
+ * Description:
+ *     This routine writes a 8 bit value to the pci configuration
+ *     space. The flag PciConfigUp indicates whether the config space
+ *     is accesible or must be set up first.
+ *
+ * Returns:
+ *     0 - indicate everything worked ok.
+ *     != 0 - error indication
+ */
+int SkPciWriteCfgByte(
+SK_AC *pAC,    /* Adapter Control structure pointer */
+int PciAddr,           /* PCI register address */
+SK_U8 Val)             /* pointer to store the read value */
+{
+       pci_write_config_byte(pAC->PciDev, PciAddr, Val);
+       return(0);
+} /* SkPciWriteCfgByte */
+
+
+/*****************************************************************************
+ *
+ *     SkDrvEvent - handle driver events
+ *
+ * Description:
+ *     This function handles events from all modules directed to the driver
+ *
+ * Context:
+ *     Is called under protection of slow path lock.
+ *
+ * Returns:
+ *     0 if everything ok
+ *     < 0  on error
+ *     
+ */
+int SkDrvEvent(
+SK_AC *pAC,            /* pointer to adapter context */
+SK_IOC IoC,            /* io-context */
+SK_U32 Event,          /* event-id */
+SK_EVPARA Param)       /* event-parameter */
+{
+SK_MBUF                *pRlmtMbuf;     /* pointer to a rlmt-mbuf structure */
+struct sk_buff *pMsg;          /* pointer to a message block */
+int            FromPort;       /* the port from which we switch away */
+int            ToPort;         /* the port we switch to */
+SK_EVPARA      NewPara;        /* parameter for further events */
+int            Stat;
+unsigned long  Flags;
+SK_BOOL                DualNet;
+
+       switch (Event) {
+       case SK_DRV_ADAP_FAIL:
+               SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_EVENT,
+                       ("ADAPTER FAIL EVENT\n"));
+               printk("%s: Adapter failed.\n", pAC->dev[0]->name);
+               /* disable interrupts */
+               SK_OUT32(pAC->IoBase, B0_IMSK, 0);
+               /* cgoos */
+               break;
+       case SK_DRV_PORT_FAIL:
+               FromPort = Param.Para32[0];
+               SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_EVENT,
+                       ("PORT FAIL EVENT, Port: %d\n", FromPort));
+               if (FromPort == 0) {
+                       printk("%s: Port A failed.\n", pAC->dev[0]->name);
+               } else {
+                       printk("%s: Port B failed.\n", pAC->dev[1]->name);
+               }
+               /* cgoos */
+               break;
+       case SK_DRV_PORT_RESET:  /* SK_U32 PortIdx */
+               /* action list 4 */
+               FromPort = Param.Para32[0];
+               SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_EVENT,
+                       ("PORT RESET EVENT, Port: %d ", FromPort));
+               NewPara.Para64 = FromPort;
+               SkPnmiEvent(pAC, IoC, SK_PNMI_EVT_XMAC_RESET, NewPara);
+               spin_lock_irqsave(
+                       &pAC->TxPort[FromPort][TX_PRIO_LOW].TxDesRingLock,
+                       Flags);
+
+               SkGeStopPort(pAC, IoC, FromPort, SK_STOP_ALL, SK_HARD_RST);
+               netif_carrier_off(pAC->dev[Param.Para32[0]]);
+               spin_unlock_irqrestore(
+                       &pAC->TxPort[FromPort][TX_PRIO_LOW].TxDesRingLock,
+                       Flags);
+               
+               /* clear rx ring from received frames */
+               ReceiveIrq(pAC, &pAC->RxPort[FromPort], SK_FALSE);
+               
+               ClearTxRing(pAC, &pAC->TxPort[FromPort][TX_PRIO_LOW]);
+               spin_lock_irqsave(
+                       &pAC->TxPort[FromPort][TX_PRIO_LOW].TxDesRingLock,
+                       Flags);
+               
+               /* tschilling: Handling of return value inserted. */
+               if (SkGeInitPort(pAC, IoC, FromPort)) {
+                       if (FromPort == 0) {
+                               printk("%s: SkGeInitPort A failed.\n", pAC->dev[0]->name);
+                       } else {
+                               printk("%s: SkGeInitPort B failed.\n", pAC->dev[1]->name);
+                       }
+               }
+               SkAddrMcUpdate(pAC,IoC, FromPort);
+               PortReInitBmu(pAC, FromPort);
+               SkGePollTxD(pAC, IoC, FromPort, SK_TRUE);
+               ClearAndStartRx(pAC, FromPort);
+               spin_unlock_irqrestore(
+                       &pAC->TxPort[FromPort][TX_PRIO_LOW].TxDesRingLock,
+                       Flags);
+               break;
+       case SK_DRV_NET_UP:      /* SK_U32 PortIdx */
+       {       struct net_device *dev = pAC->dev[Param.Para32[0]];
+               /* action list 5 */
+               FromPort = Param.Para32[0];
+               SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_EVENT,
+                       ("NET UP EVENT, Port: %d ", Param.Para32[0]));
+               /* Mac update */
+               SkAddrMcUpdate(pAC,IoC, FromPort);
+
+               if (DoPrintInterfaceChange) {
+               printk("%s: network connection up using"
+                       " port %c\n", pAC->dev[Param.Para32[0]]->name, 'A'+Param.Para32[0]);
+
+               /* tschilling: Values changed according to LinkSpeedUsed. */
+               Stat = pAC->GIni.GP[FromPort].PLinkSpeedUsed;
+               if (Stat == SK_LSPEED_STAT_10MBPS) {
+                       printk("    speed:           10\n");
+               } else if (Stat == SK_LSPEED_STAT_100MBPS) {
+                       printk("    speed:           100\n");
+               } else if (Stat == SK_LSPEED_STAT_1000MBPS) {
+                       printk("    speed:           1000\n");
+               } else {
+                       printk("    speed:           unknown\n");
+               }
+
+
+               Stat = pAC->GIni.GP[FromPort].PLinkModeStatus;
+               if (Stat == SK_LMODE_STAT_AUTOHALF ||
+                       Stat == SK_LMODE_STAT_AUTOFULL) {
+                       printk("    autonegotiation: yes\n");
+               }
+               else {
+                       printk("    autonegotiation: no\n");
+               }
+               if (Stat == SK_LMODE_STAT_AUTOHALF ||
+                       Stat == SK_LMODE_STAT_HALF) {
+                       printk("    duplex mode:     half\n");
+               }
+               else {
+                       printk("    duplex mode:     full\n");
+               }
+               Stat = pAC->GIni.GP[FromPort].PFlowCtrlStatus;
+               if (Stat == SK_FLOW_STAT_REM_SEND ) {
+                       printk("    flowctrl:        remote send\n");
+               }
+               else if (Stat == SK_FLOW_STAT_LOC_SEND ){
+                       printk("    flowctrl:        local send\n");
+               }
+               else if (Stat == SK_FLOW_STAT_SYMMETRIC ){
+                       printk("    flowctrl:        symmetric\n");
+               }
+               else {
+                       printk("    flowctrl:        none\n");
+               }
+               
+               /* tschilling: Check against CopperType now. */
+               if ((pAC->GIni.GICopperType == SK_TRUE) &&
+                       (pAC->GIni.GP[FromPort].PLinkSpeedUsed ==
+                       SK_LSPEED_STAT_1000MBPS)) {
+                       Stat = pAC->GIni.GP[FromPort].PMSStatus;
+                       if (Stat == SK_MS_STAT_MASTER ) {
+                               printk("    role:            master\n");
+                       }
+                       else if (Stat == SK_MS_STAT_SLAVE ) {
+                               printk("    role:            slave\n");
+                       }
+                       else {
+                               printk("    role:            ???\n");
+                       }
+               }
+
+               /* 
+                  Display dim (dynamic interrupt moderation) 
+                  informations
+                */
+               if (pAC->DynIrqModInfo.IntModTypeSelect == C_INT_MOD_STATIC)
+                       printk("    irq moderation:  static (%d ints/sec)\n",
+                                       pAC->DynIrqModInfo.MaxModIntsPerSec);
+               else if (pAC->DynIrqModInfo.IntModTypeSelect == C_INT_MOD_DYNAMIC)
+                       printk("    irq moderation:  dynamic (%d ints/sec)\n",
+                                       pAC->DynIrqModInfo.MaxModIntsPerSec);
+               else
+                       printk("    irq moderation:  disabled\n");
+
+
+               printk("    scatter-gather:  %s\n",
+                      (dev->features & NETIF_F_SG) ? "enabled" : "disabled");
+               printk("    tx-checksum:     %s\n",
+                      (dev->features & NETIF_F_IP_CSUM) ? "enabled" : "disabled");
+               printk("    rx-checksum:     %s\n",
+                      pAC->RxPort[Param.Para32[0]].RxCsum ? "enabled" : "disabled");
+
+               } else {
+                        DoPrintInterfaceChange = SK_TRUE;
+                }
+       
+               if ((Param.Para32[0] != pAC->ActivePort) &&
+                       (pAC->RlmtNets == 1)) {
+                       NewPara.Para32[0] = pAC->ActivePort;
+                       NewPara.Para32[1] = Param.Para32[0];
+                       SkEventQueue(pAC, SKGE_DRV, SK_DRV_SWITCH_INTERN,
+                               NewPara);
+               }
+
+               /* Inform the world that link protocol is up. */
+               netif_carrier_on(dev);
+               break;
+       }
+       case SK_DRV_NET_DOWN:    /* SK_U32 Reason */
+               /* action list 7 */
+               SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_EVENT,
+                       ("NET DOWN EVENT "));
+               if (DoPrintInterfaceChange) {
+                       printk("%s: network connection down\n", 
+                               pAC->dev[Param.Para32[1]]->name);
+               } else {
+                       DoPrintInterfaceChange = SK_TRUE;
+               }
+               netif_carrier_off(pAC->dev[Param.Para32[1]]);
+               break;
+       case SK_DRV_SWITCH_HARD: /* SK_U32 FromPortIdx SK_U32 ToPortIdx */
+               SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_EVENT,
+                       ("PORT SWITCH HARD "));
+       case SK_DRV_SWITCH_SOFT: /* SK_U32 FromPortIdx SK_U32 ToPortIdx */
+       /* action list 6 */
+               printk("%s: switching to port %c\n", pAC->dev[0]->name,
+                       'A'+Param.Para32[1]);
+       case SK_DRV_SWITCH_INTERN: /* SK_U32 FromPortIdx SK_U32 ToPortIdx */
+               FromPort = Param.Para32[0];
+               ToPort = Param.Para32[1];
+               SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_EVENT,
+                       ("PORT SWITCH EVENT, From: %d  To: %d (Pref %d) ",
+                       FromPort, ToPort, pAC->Rlmt.Net[0].PrefPort));
+               NewPara.Para64 = FromPort;
+               SkPnmiEvent(pAC, IoC, SK_PNMI_EVT_XMAC_RESET, NewPara);
+               NewPara.Para64 = ToPort;
+               SkPnmiEvent(pAC, IoC, SK_PNMI_EVT_XMAC_RESET, NewPara);
+               spin_lock_irqsave(
+                       &pAC->TxPort[FromPort][TX_PRIO_LOW].TxDesRingLock,
+                       Flags);
+               spin_lock(&pAC->TxPort[ToPort][TX_PRIO_LOW].TxDesRingLock);
+               SkGeStopPort(pAC, IoC, FromPort, SK_STOP_ALL, SK_SOFT_RST);
+               SkGeStopPort(pAC, IoC, ToPort, SK_STOP_ALL, SK_SOFT_RST);
+               spin_unlock(&pAC->TxPort[ToPort][TX_PRIO_LOW].TxDesRingLock);
+               spin_unlock_irqrestore(
+                       &pAC->TxPort[FromPort][TX_PRIO_LOW].TxDesRingLock,
+                       Flags);
+
+               ReceiveIrq(pAC, &pAC->RxPort[FromPort], SK_FALSE); /* clears rx ring */
+               ReceiveIrq(pAC, &pAC->RxPort[ToPort], SK_FALSE); /* clears rx ring */
+               
+               ClearTxRing(pAC, &pAC->TxPort[FromPort][TX_PRIO_LOW]);
+               ClearTxRing(pAC, &pAC->TxPort[ToPort][TX_PRIO_LOW]);
+               spin_lock_irqsave(
+                       &pAC->TxPort[FromPort][TX_PRIO_LOW].TxDesRingLock,
+                       Flags);
+               spin_lock(&pAC->TxPort[ToPort][TX_PRIO_LOW].TxDesRingLock);
+               pAC->ActivePort = ToPort;
+#if 0
+               SetQueueSizes(pAC);
+#else
+               /* tschilling: New common function with minimum size check. */
+               DualNet = SK_FALSE;
+               if (pAC->RlmtNets == 2) {
+                       DualNet = SK_TRUE;
+               }
+               
+               if (SkGeInitAssignRamToQueues(
+                       pAC,
+                       pAC->ActivePort,
+                       DualNet)) {
+                       spin_unlock(&pAC->TxPort[ToPort][TX_PRIO_LOW].TxDesRingLock);
+                       spin_unlock_irqrestore(
+                               &pAC->TxPort[FromPort][TX_PRIO_LOW].TxDesRingLock,
+                               Flags);
+                       printk("SkGeInitAssignRamToQueues failed.\n");
+                       break;
+               }
+#endif
+               /* tschilling: Handling of return values inserted. */
+               if (SkGeInitPort(pAC, IoC, FromPort) ||
+                       SkGeInitPort(pAC, IoC, ToPort)) {
+                       printk("%s: SkGeInitPort failed.\n", pAC->dev[0]->name);
+               }
+               if (Event == SK_DRV_SWITCH_SOFT) {
+                       SkMacRxTxEnable(pAC, IoC, FromPort);
+               }
+               SkMacRxTxEnable(pAC, IoC, ToPort);
+               SkAddrSwap(pAC, IoC, FromPort, ToPort);
+               SkAddrMcUpdate(pAC, IoC, FromPort);
+               SkAddrMcUpdate(pAC, IoC, ToPort);
+               PortReInitBmu(pAC, FromPort);
+               PortReInitBmu(pAC, ToPort);
+               SkGePollTxD(pAC, IoC, FromPort, SK_TRUE);
+               SkGePollTxD(pAC, IoC, ToPort, SK_TRUE);
+               ClearAndStartRx(pAC, FromPort);
+               ClearAndStartRx(pAC, ToPort);
+               spin_unlock(&pAC->TxPort[ToPort][TX_PRIO_LOW].TxDesRingLock);
+               spin_unlock_irqrestore(
+                       &pAC->TxPort[FromPort][TX_PRIO_LOW].TxDesRingLock,
+                       Flags);
+               break;
+       case SK_DRV_RLMT_SEND:   /* SK_MBUF *pMb */
+               SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_EVENT,
+                       ("RLS "));
+               pRlmtMbuf = (SK_MBUF*) Param.pParaPtr;
+               pMsg = (struct sk_buff*) pRlmtMbuf->pOs;
+               skb_put(pMsg, pRlmtMbuf->Length);
+               if (XmitFrame(pAC, &pAC->TxPort[pRlmtMbuf->PortIdx][TX_PRIO_LOW],
+                       pMsg) < 0)
+
+                       DEV_KFREE_SKB_ANY(pMsg);
+               break;
+       case SK_DRV_TIMER:
+               if (Param.Para32[0] == SK_DRV_MODERATION_TIMER) {
+                       /*
+                       ** expiration of the moderation timer implies that
+                       ** dynamic moderation is to be applied
+                       */
+                       SkDimStartModerationTimer(pAC);
+                       SkDimModerate(pAC);
+                        if (pAC->DynIrqModInfo.DisplayStats) {
+                           SkDimDisplayModerationSettings(pAC);
+                        }
+                } else if (Param.Para32[0] == SK_DRV_RX_CLEANUP_TIMER) {
+                       /*
+                       ** check if we need to check for descriptors which
+                       ** haven't been handled the last millisecs
+                       */
+                       StartDrvCleanupTimer(pAC);
+                       if (pAC->GIni.GIMacsFound == 2) {
+                               ReceiveIrq(pAC, &pAC->RxPort[1], SK_FALSE);
+                       }
+                       ReceiveIrq(pAC, &pAC->RxPort[0], SK_FALSE);
+               } else {
+                       printk("Expiration of unknown timer\n");
+               }
+               break;
+       default:
+               break;
+       }
+       SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_EVENT,
+               ("END EVENT "));
+       
+       return (0);
+} /* SkDrvEvent */
+
+
+/*****************************************************************************
+ *
+ *     SkErrorLog - log errors
+ *
+ * Description:
+ *     This function logs errors to the system buffer and to the console
+ *
+ * Returns:
+ *     0 if everything ok
+ *     < 0  on error
+ *     
+ */
+void SkErrorLog(
+SK_AC  *pAC,
+int    ErrClass,
+int    ErrNum,
+char   *pErrorMsg)
+{
+char   ClassStr[80];
+
+       switch (ErrClass) {
+       case SK_ERRCL_OTHER:
+               strcpy(ClassStr, "Other error");
+               break;
+       case SK_ERRCL_CONFIG:
+               strcpy(ClassStr, "Configuration error");
+               break;
+       case SK_ERRCL_INIT:
+               strcpy(ClassStr, "Initialization error");
+               break;
+       case SK_ERRCL_NORES:
+               strcpy(ClassStr, "Out of resources error");
+               break;
+       case SK_ERRCL_SW:
+               strcpy(ClassStr, "internal Software error");
+               break;
+       case SK_ERRCL_HW:
+               strcpy(ClassStr, "Hardware failure");
+               break;
+       case SK_ERRCL_COMM:
+               strcpy(ClassStr, "Communication error");
+               break;
+       }
+       printk(KERN_INFO "%s: -- ERROR --\n        Class:  %s\n"
+               "        Nr:  0x%x\n        Msg:  %s\n", pAC->dev[0]->name,
+               ClassStr, ErrNum, pErrorMsg);
+
+} /* SkErrorLog */
+
+#ifdef SK_DIAG_SUPPORT
+
+/*****************************************************************************
+ *
+ *     SkDrvEnterDiagMode - handles DIAG attach request
+ *
+ * Description:
+ *     Notify the kernel to NOT access the card any longer due to DIAG
+ *     Deinitialize the Card
+ *
+ * Returns:
+ *     int
+ */
+int SkDrvEnterDiagMode(
+SK_AC   *pAc)   /* pointer to adapter context */
+{
+       DEV_NET *pNet = netdev_priv(pAc->dev[0]);
+       SK_AC   *pAC  = pNet->pAC;
+
+       SK_MEMCPY(&(pAc->PnmiBackup), &(pAc->PnmiStruct), 
+                       sizeof(SK_PNMI_STRUCT_DATA));
+
+       pAC->DiagModeActive = DIAG_ACTIVE;
+       if (pAC->BoardLevel > SK_INIT_DATA) {
+               if (netif_running(pAC->dev[0])) {
+                       pAC->WasIfUp[0] = SK_TRUE;
+                       pAC->DiagFlowCtrl = SK_TRUE; /* for SkGeClose      */
+                       DoPrintInterfaceChange = SK_FALSE;
+                       SkDrvDeInitAdapter(pAC, 0);  /* performs SkGeClose */
+               } else {
+                       pAC->WasIfUp[0] = SK_FALSE;
+               }
+               if (pNet != netdev_priv(pAC->dev[1])) {
+                       pNet = netdev_priv(pAC->dev[1]);
+                       if (netif_running(pAC->dev[1])) {
+                               pAC->WasIfUp[1] = SK_TRUE;
+                               pAC->DiagFlowCtrl = SK_TRUE; /* for SkGeClose */
+                               DoPrintInterfaceChange = SK_FALSE;
+                               SkDrvDeInitAdapter(pAC, 1);  /* do SkGeClose  */
+                       } else {
+                               pAC->WasIfUp[1] = SK_FALSE;
+                       }
+               }
+               pAC->BoardLevel = SK_INIT_DATA;
+       }
+       return(0);
+}
+
+/*****************************************************************************
+ *
+ *     SkDrvLeaveDiagMode - handles DIAG detach request
+ *
+ * Description:
+ *     Notify the kernel to may access the card again after use by DIAG
+ *     Initialize the Card
+ *
+ * Returns:
+ *     int
+ */
+int SkDrvLeaveDiagMode(
+SK_AC   *pAc)   /* pointer to adapter control context */
+{ 
+       SK_MEMCPY(&(pAc->PnmiStruct), &(pAc->PnmiBackup), 
+                       sizeof(SK_PNMI_STRUCT_DATA));
+       pAc->DiagModeActive    = DIAG_NOTACTIVE;
+       pAc->Pnmi.DiagAttached = SK_DIAG_IDLE;
+        if (pAc->WasIfUp[0] == SK_TRUE) {
+                pAc->DiagFlowCtrl = SK_TRUE; /* for SkGeClose */
+               DoPrintInterfaceChange = SK_FALSE;
+                SkDrvInitAdapter(pAc, 0);    /* first device  */
+        }
+        if (pAc->WasIfUp[1] == SK_TRUE) {
+                pAc->DiagFlowCtrl = SK_TRUE; /* for SkGeClose */
+               DoPrintInterfaceChange = SK_FALSE;
+                SkDrvInitAdapter(pAc, 1);    /* second device */
+        }
+       return(0);
+}
+
+/*****************************************************************************
+ *
+ *     ParseDeviceNbrFromSlotName - Evaluate PCI device number
+ *
+ * Description:
+ *     This function parses the PCI slot name information string and will
+ *     retrieve the devcie number out of it. The slot_name maintianed by
+ *     linux is in the form of '02:0a.0', whereas the first two characters 
+ *     represent the bus number in hex (in the sample above this is 
+ *     pci bus 0x02) and the next two characters the device number (0x0a).
+ *
+ * Returns:
+ *     SK_U32: The device number from the PCI slot name
+ */ 
+
+static SK_U32 ParseDeviceNbrFromSlotName(
+const char *SlotName)   /* pointer to pci slot name eg. '02:0a.0' */
+{
+       char    *CurrCharPos    = (char *) SlotName;
+       int     FirstNibble     = -1;
+       int     SecondNibble    = -1;
+       SK_U32  Result          =  0;
+
+       while (*CurrCharPos != '\0') {
+               if (*CurrCharPos == ':') { 
+                       while (*CurrCharPos != '.') {
+                               CurrCharPos++;  
+                               if (    (*CurrCharPos >= '0') && 
+                                       (*CurrCharPos <= '9')) {
+                                       if (FirstNibble == -1) {
+                                               /* dec. value for '0' */
+                                               FirstNibble = *CurrCharPos - 48;
+                                       } else {
+                                               SecondNibble = *CurrCharPos - 48;
+                                       }  
+                               } else if (     (*CurrCharPos >= 'a') && 
+                                               (*CurrCharPos <= 'f')  ) {
+                                       if (FirstNibble == -1) {
+                                               FirstNibble = *CurrCharPos - 87; 
+                                       } else {
+                                               SecondNibble = *CurrCharPos - 87; 
+                                       }
+                               } else {
+                                       Result = 0;
+                               }
+                       }
+
+                       Result = FirstNibble;
+                       Result = Result << 4; /* first nibble is higher one */
+                       Result = Result | SecondNibble;
+               }
+               CurrCharPos++;   /* next character */
+       }
+       return (Result);
+}
+
+/****************************************************************************
+ *
+ *     SkDrvDeInitAdapter - deinitialize adapter (this function is only 
+ *                             called if Diag attaches to that card)
+ *
+ * Description:
+ *     Close initialized adapter.
+ *
+ * Returns:
+ *     0 - on success
+ *     error code - on error
+ */
+static int SkDrvDeInitAdapter(
+SK_AC   *pAC,          /* pointer to adapter context   */
+int      devNbr)       /* what device is to be handled */
+{
+       struct SK_NET_DEVICE *dev;
+
+       dev = pAC->dev[devNbr];
+
+       /* On Linux 2.6 the network driver does NOT mess with reference
+       ** counts.  The driver MUST be able to be unloaded at any time
+       ** due to the possibility of hotplug.
+       */
+       if (SkGeClose(dev) != 0) {
+               return (-1);
+       }
+       return (0);
+
+} /* SkDrvDeInitAdapter() */
+
+/****************************************************************************
+ *
+ *     SkDrvInitAdapter - Initialize adapter (this function is only 
+ *                             called if Diag deattaches from that card)
+ *
+ * Description:
+ *     Close initialized adapter.
+ *
+ * Returns:
+ *     0 - on success
+ *     error code - on error
+ */
+static int SkDrvInitAdapter(
+SK_AC   *pAC,          /* pointer to adapter context   */
+int      devNbr)       /* what device is to be handled */
+{
+       struct SK_NET_DEVICE *dev;
+
+       dev = pAC->dev[devNbr];
+
+       if (SkGeOpen(dev) != 0) {
+               return (-1);
+       }
+
+       /*
+       ** Use correct MTU size and indicate to kernel TX queue can be started
+       */ 
+       if (SkGeChangeMtu(dev, dev->mtu) != 0) {
+               return (-1);
+       } 
+       return (0);
+
+} /* SkDrvInitAdapter */
+
+#endif
+
+#ifdef DEBUG
+/****************************************************************************/
+/* "debug only" section *****************************************************/
+/****************************************************************************/
+
+
+/*****************************************************************************
+ *
+ *     DumpMsg - print a frame
+ *
+ * Description:
+ *     This function prints frames to the system logfile/to the console.
+ *
+ * Returns: N/A
+ *     
+ */
+static void DumpMsg(struct sk_buff *skb, char *str)
+{
+       int     msglen;
+
+       if (skb == NULL) {
+               printk("DumpMsg(): NULL-Message\n");
+               return;
+       }
+
+       if (skb->data == NULL) {
+               printk("DumpMsg(): Message empty\n");
+               return;
+       }
+
+       msglen = skb->len;
+       if (msglen > 64)
+               msglen = 64;
+
+       printk("--- Begin of message from %s , len %d (from %d) ----\n", str, msglen, skb->len);
+
+       DumpData((char *)skb->data, msglen);
+
+       printk("------- End of message ---------\n");
+} /* DumpMsg */
+
+
+
+/*****************************************************************************
+ *
+ *     DumpData - print a data area
+ *
+ * Description:
+ *     This function prints a area of data to the system logfile/to the
+ *     console.
+ *
+ * Returns: N/A
+ *     
+ */
+static void DumpData(char *p, int size)
+{
+register int    i;
+int    haddr, addr;
+char   hex_buffer[180];
+char   asc_buffer[180];
+char   HEXCHAR[] = "0123456789ABCDEF";
+
+       addr = 0;
+       haddr = 0;
+       hex_buffer[0] = 0;
+       asc_buffer[0] = 0;
+       for (i=0; i < size; ) {
+               if (*p >= '0' && *p <='z')
+                       asc_buffer[addr] = *p;
+               else
+                       asc_buffer[addr] = '.';
+               addr++;
+               asc_buffer[addr] = 0;
+               hex_buffer[haddr] = HEXCHAR[(*p & 0xf0) >> 4];
+               haddr++;
+               hex_buffer[haddr] = HEXCHAR[*p & 0x0f];
+               haddr++;
+               hex_buffer[haddr] = ' ';
+               haddr++;
+               hex_buffer[haddr] = 0;
+               p++;
+               i++;
+               if (i%16 == 0) {
+                       printk("%s  %s\n", hex_buffer, asc_buffer);
+                       addr = 0;
+                       haddr = 0;
+               }
+       }
+} /* DumpData */
+
+
+/*****************************************************************************
+ *
+ *     DumpLong - print a data area as long values
+ *
+ * Description:
+ *     This function prints a area of data to the system logfile/to the
+ *     console.
+ *
+ * Returns: N/A
+ *     
+ */
+static void DumpLong(char *pc, int size)
+{
+register int    i;
+int    haddr, addr;
+char   hex_buffer[180];
+char   asc_buffer[180];
+char   HEXCHAR[] = "0123456789ABCDEF";
+long   *p;
+int    l;
+
+       addr = 0;
+       haddr = 0;
+       hex_buffer[0] = 0;
+       asc_buffer[0] = 0;
+       p = (long*) pc;
+       for (i=0; i < size; ) {
+               l = (long) *p;
+               hex_buffer[haddr] = HEXCHAR[(l >> 28) & 0xf];
+               haddr++;
+               hex_buffer[haddr] = HEXCHAR[(l >> 24) & 0xf];
+               haddr++;
+               hex_buffer[haddr] = HEXCHAR[(l >> 20) & 0xf];
+               haddr++;
+               hex_buffer[haddr] = HEXCHAR[(l >> 16) & 0xf];
+               haddr++;
+               hex_buffer[haddr] = HEXCHAR[(l >> 12) & 0xf];
+               haddr++;
+               hex_buffer[haddr] = HEXCHAR[(l >> 8) & 0xf];
+               haddr++;
+               hex_buffer[haddr] = HEXCHAR[(l >> 4) & 0xf];
+               haddr++;
+               hex_buffer[haddr] = HEXCHAR[l & 0x0f];
+               haddr++;
+               hex_buffer[haddr] = ' ';
+               haddr++;
+               hex_buffer[haddr] = 0;
+               p++;
+               i++;
+               if (i%8 == 0) {
+                       printk("%4x %s\n", (i-8)*4, hex_buffer);
+                       haddr = 0;
+               }
+       }
+       printk("------------------------\n");
+} /* DumpLong */
+
+#endif
+
+static int __devinit skge_probe_one(struct pci_dev *pdev,
+               const struct pci_device_id *ent)
+{
+       SK_AC                   *pAC;
+       DEV_NET                 *pNet = NULL;
+       struct net_device       *dev = NULL;
+       static int boards_found = 0;
+       int error = -ENODEV;
+       int using_dac = 0;
+       char DeviceStr[80];
+
+       if (pci_enable_device(pdev))
+               goto out;
+       /* Configure DMA attributes. */
+       if (sizeof(dma_addr_t) > sizeof(u32) &&
+           !(error = pci_set_dma_mask(pdev, DMA_64BIT_MASK))) {
+               using_dac = 1;
+               error = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK);
+               if (error < 0) {
+                       printk(KERN_ERR "sk98lin %s unable to obtain 64 bit DMA "
+                              "for consistent allocations\n", pci_name(pdev));
+                       goto out_disable_device;
+               }
+       } else {
+               error = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
+               if (error) {
+                       printk(KERN_ERR "sk98lin %s no usable DMA configuration\n",
+                              pci_name(pdev));
+                       goto out_disable_device;
+               }
+       }
+
+       error = -ENOMEM;
+       dev = alloc_etherdev(sizeof(DEV_NET));
+       if (!dev) {
+               printk(KERN_ERR "sk98lin: unable to allocate etherdev "
+                      "structure!\n");
+               goto out_disable_device;
+       }
+
+       pNet = netdev_priv(dev);
+       pNet->pAC = kzalloc(sizeof(SK_AC), GFP_KERNEL);
+       if (!pNet->pAC) {
+               printk(KERN_ERR "sk98lin: unable to allocate adapter "
+                      "structure!\n");
+               goto out_free_netdev;
+       }
+
+       pAC = pNet->pAC;
+       pAC->PciDev = pdev;
+
+       pAC->dev[0] = dev;
+       pAC->dev[1] = dev;
+       pAC->CheckQueue = SK_FALSE;
+
+       dev->irq = pdev->irq;
+
+       error = SkGeInitPCI(pAC);
+       if (error) {
+               printk(KERN_ERR "sk98lin: PCI setup failed: %i\n", error);
+               goto out_free_netdev;
+       }
+
+       SET_MODULE_OWNER(dev);
+       dev->open =             &SkGeOpen;
+       dev->stop =             &SkGeClose;
+       dev->hard_start_xmit =  &SkGeXmit;
+       dev->get_stats =        &SkGeStats;
+       dev->set_multicast_list = &SkGeSetRxMode;
+       dev->set_mac_address =  &SkGeSetMacAddr;
+       dev->do_ioctl =         &SkGeIoctl;
+       dev->change_mtu =       &SkGeChangeMtu;
+#ifdef CONFIG_NET_POLL_CONTROLLER
+       dev->poll_controller =  &SkGePollController;
+#endif
+       SET_NETDEV_DEV(dev, &pdev->dev);
+       SET_ETHTOOL_OPS(dev, &SkGeEthtoolOps);
+
+       /* Use only if yukon hardware */
+       if (pAC->ChipsetType) {
+#ifdef USE_SK_TX_CHECKSUM
+               dev->features |= NETIF_F_IP_CSUM;
+#endif
+#ifdef SK_ZEROCOPY
+               dev->features |= NETIF_F_SG;
+#endif
+#ifdef USE_SK_RX_CHECKSUM
+               pAC->RxPort[0].RxCsum = 1;
+#endif
+       }
+
+       if (using_dac)
+               dev->features |= NETIF_F_HIGHDMA;
+
+       pAC->Index = boards_found++;
+
+       error = SkGeBoardInit(dev, pAC);
+       if (error)
+               goto out_free_netdev;
+
+       /* Read Adapter name from VPD */
+       if (ProductStr(pAC, DeviceStr, sizeof(DeviceStr)) != 0) {
+               error = -EIO;
+               printk(KERN_ERR "sk98lin: Could not read VPD data.\n");
+               goto out_free_resources;
+       }
+
+       /* Register net device */
+       error = register_netdev(dev);
+       if (error) {
+               printk(KERN_ERR "sk98lin: Could not register device.\n");
+               goto out_free_resources;
+       }
+
+       /* Print adapter specific string from vpd */
+       printk("%s: %s\n", dev->name, DeviceStr);
+
+       /* Print configuration settings */
+       printk("      PrefPort:%c  RlmtMode:%s\n",
+               'A' + pAC->Rlmt.Net[0].Port[pAC->Rlmt.Net[0].PrefPort]->PortNumber,
+               (pAC->RlmtMode==0)  ? "Check Link State" :
+               ((pAC->RlmtMode==1) ? "Check Link State" :
+               ((pAC->RlmtMode==3) ? "Check Local Port" :
+               ((pAC->RlmtMode==7) ? "Check Segmentation" :
+               ((pAC->RlmtMode==17) ? "Dual Check Link State" :"Error")))));
+
+       SkGeYellowLED(pAC, pAC->IoBase, 1);
+
+       memcpy(&dev->dev_addr, &pAC->Addr.Net[0].CurrentMacAddress, 6);
+       memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
+
+       pNet->PortNr = 0;
+       pNet->NetNr  = 0;
+
+       boards_found++;
+
+       pci_set_drvdata(pdev, dev);
+
+       /* More then one port found */
+       if ((pAC->GIni.GIMacsFound == 2 ) && (pAC->RlmtNets == 2)) {
+               dev = alloc_etherdev(sizeof(DEV_NET));
+               if (!dev) {
+                       printk(KERN_ERR "sk98lin: unable to allocate etherdev "
+                               "structure!\n");
+                       goto single_port;
+               }
+
+               pNet          = netdev_priv(dev);
+               pNet->PortNr  = 1;
+               pNet->NetNr   = 1;
+               pNet->pAC     = pAC;
+
+               dev->open               = &SkGeOpen;
+               dev->stop               = &SkGeClose;
+               dev->hard_start_xmit    = &SkGeXmit;
+               dev->get_stats          = &SkGeStats;
+               dev->set_multicast_list = &SkGeSetRxMode;
+               dev->set_mac_address    = &SkGeSetMacAddr;
+               dev->do_ioctl           = &SkGeIoctl;
+               dev->change_mtu         = &SkGeChangeMtu;
+               SET_NETDEV_DEV(dev, &pdev->dev);
+               SET_ETHTOOL_OPS(dev, &SkGeEthtoolOps);
+
+               if (pAC->ChipsetType) {
+#ifdef USE_SK_TX_CHECKSUM
+                       dev->features |= NETIF_F_IP_CSUM;
+#endif
+#ifdef SK_ZEROCOPY
+                       dev->features |= NETIF_F_SG;
+#endif
+#ifdef USE_SK_RX_CHECKSUM
+                       pAC->RxPort[1].RxCsum = 1;
+#endif
+               }
+
+               if (using_dac)
+                       dev->features |= NETIF_F_HIGHDMA;
+
+               error = register_netdev(dev);
+               if (error) {
+                       printk(KERN_ERR "sk98lin: Could not register device"
+                              " for second port. (%d)\n", error);
+                       free_netdev(dev);
+                       goto single_port;
+               }
+
+               pAC->dev[1]   = dev;
+               memcpy(&dev->dev_addr,
+                      &pAC->Addr.Net[1].CurrentMacAddress, 6);
+               memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
+
+               printk("%s: %s\n", dev->name, DeviceStr);
+               printk("      PrefPort:B  RlmtMode:Dual Check Link State\n");
+       }
+
+single_port:
+
+       /* Save the hardware revision */
+       pAC->HWRevision = (((pAC->GIni.GIPciHwRev >> 4) & 0x0F)*10) +
+               (pAC->GIni.GIPciHwRev & 0x0F);
+
+       /* Set driver globals */
+       pAC->Pnmi.pDriverFileName    = DRIVER_FILE_NAME;
+       pAC->Pnmi.pDriverReleaseDate = DRIVER_REL_DATE;
+
+       memset(&pAC->PnmiBackup, 0, sizeof(SK_PNMI_STRUCT_DATA));
+       memcpy(&pAC->PnmiBackup, &pAC->PnmiStruct, sizeof(SK_PNMI_STRUCT_DATA));
+
+       return 0;
+
+ out_free_resources:
+       FreeResources(dev);
+ out_free_netdev:
+       free_netdev(dev);
+ out_disable_device:
+       pci_disable_device(pdev);
+ out:
+       return error;
+}
+
+static void __devexit skge_remove_one(struct pci_dev *pdev)
+{
+       struct net_device *dev = pci_get_drvdata(pdev);
+       DEV_NET *pNet = netdev_priv(dev);
+       SK_AC *pAC = pNet->pAC;
+       struct net_device *otherdev = pAC->dev[1];
+
+       unregister_netdev(dev);
+
+       SkGeYellowLED(pAC, pAC->IoBase, 0);
+
+       if (pAC->BoardLevel == SK_INIT_RUN) {
+               SK_EVPARA EvPara;
+               unsigned long Flags;
+
+               /* board is still alive */
+               spin_lock_irqsave(&pAC->SlowPathLock, Flags);
+               EvPara.Para32[0] = 0;
+               EvPara.Para32[1] = -1;
+               SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_STOP, EvPara);
+               EvPara.Para32[0] = 1;
+               EvPara.Para32[1] = -1;
+               SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_STOP, EvPara);
+               SkEventDispatcher(pAC, pAC->IoBase);
+               /* disable interrupts */
+               SK_OUT32(pAC->IoBase, B0_IMSK, 0);
+               SkGeDeInit(pAC, pAC->IoBase);
+               spin_unlock_irqrestore(&pAC->SlowPathLock, Flags);
+               pAC->BoardLevel = SK_INIT_DATA;
+               /* We do NOT check here, if IRQ was pending, of course*/
+       }
+
+       if (pAC->BoardLevel == SK_INIT_IO) {
+               /* board is still alive */
+               SkGeDeInit(pAC, pAC->IoBase);
+               pAC->BoardLevel = SK_INIT_DATA;
+       }
+
+       FreeResources(dev);
+       free_netdev(dev);
+       if (otherdev != dev)
+               free_netdev(otherdev);
+       kfree(pAC);
+}
+
+#ifdef CONFIG_PM
+static int skge_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+       struct net_device *dev = pci_get_drvdata(pdev);
+       DEV_NET *pNet = netdev_priv(dev);
+       SK_AC *pAC = pNet->pAC;
+       struct net_device *otherdev = pAC->dev[1];
+
+       if (netif_running(dev)) {
+               netif_carrier_off(dev);
+               DoPrintInterfaceChange = SK_FALSE;
+               SkDrvDeInitAdapter(pAC, 0);  /* performs SkGeClose */
+               netif_device_detach(dev);
+       }
+       if (otherdev != dev) {
+               if (netif_running(otherdev)) {
+                       netif_carrier_off(otherdev);
+                       DoPrintInterfaceChange = SK_FALSE;
+                       SkDrvDeInitAdapter(pAC, 1);  /* performs SkGeClose */
+                       netif_device_detach(otherdev);
+               }
+       }
+
+       pci_save_state(pdev);
+       pci_enable_wake(pdev, pci_choose_state(pdev, state), 0);
+       if (pAC->AllocFlag & SK_ALLOC_IRQ) {
+               free_irq(dev->irq, dev);
+       }
+       pci_disable_device(pdev);
+       pci_set_power_state(pdev, pci_choose_state(pdev, state));
+
+       return 0;
+}
+
+static int skge_resume(struct pci_dev *pdev)
+{
+       struct net_device *dev = pci_get_drvdata(pdev);
+       DEV_NET *pNet = netdev_priv(dev);
+       SK_AC *pAC = pNet->pAC;
+       struct net_device *otherdev = pAC->dev[1];
+       int ret;
+
+       pci_set_power_state(pdev, PCI_D0);
+       pci_restore_state(pdev);
+       ret = pci_enable_device(pdev);
+       if (ret) {
+               printk(KERN_WARNING "sk98lin: unable to enable device %s "
+                               "in resume\n", dev->name);
+               goto err_out;
+       }
+       pci_set_master(pdev);
+       if (pAC->GIni.GIMacsFound == 2)
+               ret = request_irq(dev->irq, SkGeIsr, IRQF_SHARED, "sk98lin", dev);
+       else
+               ret = request_irq(dev->irq, SkGeIsrOnePort, IRQF_SHARED, "sk98lin", dev);
+       if (ret) {
+               printk(KERN_WARNING "sk98lin: unable to acquire IRQ %d\n", dev->irq);
+               ret = -EBUSY;
+               goto err_out_disable_pdev;
+       }
+
+       netif_device_attach(dev);
+       if (netif_running(dev)) {
+               DoPrintInterfaceChange = SK_FALSE;
+               SkDrvInitAdapter(pAC, 0);    /* first device  */
+       }
+       if (otherdev != dev) {
+               netif_device_attach(otherdev);
+               if (netif_running(otherdev)) {
+                       DoPrintInterfaceChange = SK_FALSE;
+                       SkDrvInitAdapter(pAC, 1);    /* second device  */
+               }
+       }
+
+       return 0;
+
+err_out_disable_pdev:
+       pci_disable_device(pdev);
+err_out:
+       pAC->AllocFlag &= ~SK_ALLOC_IRQ;
+       dev->irq = 0;
+       return ret;
+}
+#else
+#define skge_suspend NULL
+#define skge_resume NULL
+#endif
+
+static struct pci_device_id skge_pci_tbl[] = {
+#ifdef SK98LIN_ALL_DEVICES
+       { PCI_VENDOR_ID_3COM, 0x1700, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+       { PCI_VENDOR_ID_3COM, 0x80eb, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+#endif
+#ifdef GENESIS
+       /* Generic SysKonnect SK-98xx Gigabit Ethernet Server Adapter */        
+       { PCI_VENDOR_ID_SYSKONNECT, 0x4300, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+#endif
+       /* Generic SysKonnect SK-98xx V2.0 Gigabit Ethernet Adapter */  
+       { PCI_VENDOR_ID_SYSKONNECT, 0x4320, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+#ifdef SK98LIN_ALL_DEVICES
+/* DLink card does not have valid VPD so this driver gags
+ *     { PCI_VENDOR_ID_DLINK, 0x4c00, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+ */
+       { PCI_VENDOR_ID_MARVELL, 0x4320, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+       { PCI_VENDOR_ID_MARVELL, 0x5005, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+       { PCI_VENDOR_ID_CNET, 0x434e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+       { PCI_VENDOR_ID_LINKSYS, 0x1032, PCI_ANY_ID, 0x0015, },
+       { PCI_VENDOR_ID_LINKSYS, 0x1064, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+#endif
+       { 0 }
+};
+
+MODULE_DEVICE_TABLE(pci, skge_pci_tbl);
+
+static struct pci_driver skge_driver = {
+       .name           = "sk98lin",
+       .id_table       = skge_pci_tbl,
+       .probe          = skge_probe_one,
+       .remove         = __devexit_p(skge_remove_one),
+       .suspend        = skge_suspend,
+       .resume         = skge_resume,
+};
+
+static int __init skge_init(void)
+{
+       printk(KERN_NOTICE "sk98lin: driver has been replaced by the skge driver"
+              " and is scheduled for removal\n");
+
+       return pci_register_driver(&skge_driver);
+}
+
+static void __exit skge_exit(void)
+{
+       pci_unregister_driver(&skge_driver);
+}
+
+module_init(skge_init);
+module_exit(skge_exit);
diff --git a/drivers/net/sk98lin/skgehwt.c b/drivers/net/sk98lin/skgehwt.c
new file mode 100644 (file)
index 0000000..db67099
--- /dev/null
@@ -0,0 +1,171 @@
+/******************************************************************************
+ *
+ * Name:       skgehwt.c
+ * Project:    Gigabit Ethernet Adapters, Event Scheduler Module
+ * Version:    $Revision: 1.15 $
+ * Date:       $Date: 2003/09/16 13:41:23 $
+ * Purpose:    Hardware Timer
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *     (C)Copyright 1998-2002 SysKonnect GmbH.
+ *     (C)Copyright 2002-2003 Marvell.
+ *
+ *     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.
+ *
+ *     The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/*
+ *     Event queue and dispatcher
+ */
+#if (defined(DEBUG) || ((!defined(LINT)) && (!defined(SK_SLIM))))
+static const char SysKonnectFileId[] =
+       "@(#) $Id: skgehwt.c,v 1.15 2003/09/16 13:41:23 rschmidt Exp $ (C) Marvell.";
+#endif
+
+#include "h/skdrv1st.h"                /* Driver Specific Definitions */
+#include "h/skdrv2nd.h"                /* Adapter Control- and Driver specific Def. */
+
+#ifdef __C2MAN__
+/*
+ *   Hardware Timer function queue management.
+ */
+intro()
+{}
+#endif
+
+/*
+ * Prototypes of local functions.
+ */
+#define        SK_HWT_MAX      (65000)
+
+/* correction factor */
+#define        SK_HWT_FAC      (1000 * (SK_U32)pAC->GIni.GIHstClkFact / 100)
+
+/*
+ * Initialize hardware timer.
+ *
+ * Must be called during init level 1.
+ */
+void   SkHwtInit(
+SK_AC  *pAC,   /* Adapters context */
+SK_IOC Ioc)    /* IoContext */
+{
+       pAC->Hwt.TStart = 0 ;
+       pAC->Hwt.TStop  = 0 ;
+       pAC->Hwt.TActive = SK_FALSE;
+
+       SkHwtStop(pAC, Ioc);
+}
+
+/*
+ *
+ * Start hardware timer (clock ticks are 16us).
+ *
+ */
+void   SkHwtStart(
+SK_AC  *pAC,   /* Adapters context */
+SK_IOC Ioc,    /* IoContext */
+SK_U32 Time)   /* Time in units of 16us to load the timer with. */
+{
+       SK_U32  Cnt;
+
+       if (Time > SK_HWT_MAX)
+               Time = SK_HWT_MAX;
+
+       pAC->Hwt.TStart = Time;
+       pAC->Hwt.TStop = 0L;
+
+       Cnt = Time;
+
+       /*
+        * if time < 16 us
+        *      time = 16 us
+        */
+       if (!Cnt) {
+               Cnt++;
+       }
+
+       SK_OUT32(Ioc, B2_TI_INI, Cnt * SK_HWT_FAC);
+       
+       SK_OUT16(Ioc, B2_TI_CTRL, TIM_START);   /* Start timer. */
+
+       pAC->Hwt.TActive = SK_TRUE;
+}
+
+/*
+ * Stop hardware timer.
+ * and clear the timer IRQ
+ */
+void   SkHwtStop(
+SK_AC  *pAC,   /* Adapters context */
+SK_IOC Ioc)    /* IoContext */
+{
+       SK_OUT16(Ioc, B2_TI_CTRL, TIM_STOP);
+       
+       SK_OUT16(Ioc, B2_TI_CTRL, TIM_CLR_IRQ);
+
+       pAC->Hwt.TActive = SK_FALSE;
+}
+
+
+/*
+ *     Stop hardware timer and read time elapsed since last start.
+ *
+ * returns
+ *     The elapsed time since last start in units of 16us.
+ *
+ */
+SK_U32 SkHwtRead(
+SK_AC  *pAC,   /* Adapters context */
+SK_IOC Ioc)    /* IoContext */
+{
+       SK_U32  TRead;
+       SK_U32  IStatus;
+
+       if (pAC->Hwt.TActive) {
+               
+               SkHwtStop(pAC, Ioc);
+
+               SK_IN32(Ioc, B2_TI_VAL, &TRead);
+               TRead /= SK_HWT_FAC;
+
+               SK_IN32(Ioc, B0_ISRC, &IStatus);
+
+               /* Check if timer expired (or wraped around) */
+               if ((TRead > pAC->Hwt.TStart) || (IStatus & IS_TIMINT)) {
+                       
+                       SkHwtStop(pAC, Ioc);
+                       
+                       pAC->Hwt.TStop = pAC->Hwt.TStart;
+               }
+               else {
+                       
+                       pAC->Hwt.TStop = pAC->Hwt.TStart - TRead;
+               }
+       }
+       return(pAC->Hwt.TStop);
+}
+
+/*
+ * interrupt source= timer
+ */
+void   SkHwtIsr(
+SK_AC  *pAC,   /* Adapters context */
+SK_IOC Ioc)    /* IoContext */
+{
+       SkHwtStop(pAC, Ioc);
+       
+       pAC->Hwt.TStop = pAC->Hwt.TStart;
+       
+       SkTimerDone(pAC, Ioc);
+}
+
+/* End of file */
diff --git a/drivers/net/sk98lin/skgeinit.c b/drivers/net/sk98lin/skgeinit.c
new file mode 100644 (file)
index 0000000..67f1d6a
--- /dev/null
@@ -0,0 +1,2005 @@
+/******************************************************************************
+ *
+ * Name:       skgeinit.c
+ * Project:    Gigabit Ethernet Adapters, Common Modules
+ * Version:    $Revision: 1.97 $
+ * Date:       $Date: 2003/10/02 16:45:31 $
+ * Purpose:    Contains functions to initialize the adapter
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *     (C)Copyright 1998-2002 SysKonnect.
+ *     (C)Copyright 2002-2003 Marvell.
+ *
+ *     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.
+ *
+ *     The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+#include "h/skdrv1st.h"
+#include "h/skdrv2nd.h"
+
+/* global variables ***********************************************************/
+
+/* local variables ************************************************************/
+
+#if (defined(DEBUG) || ((!defined(LINT)) && (!defined(SK_SLIM))))
+static const char SysKonnectFileId[] =
+       "@(#) $Id: skgeinit.c,v 1.97 2003/10/02 16:45:31 rschmidt Exp $ (C) Marvell.";
+#endif
+
+struct s_QOffTab {
+       int     RxQOff;         /* Receive Queue Address Offset */
+       int     XsQOff;         /* Sync Tx Queue Address Offset */
+       int     XaQOff;         /* Async Tx Queue Address Offset */
+};
+static struct s_QOffTab QOffTab[] = {
+       {Q_R1, Q_XS1, Q_XA1}, {Q_R2, Q_XS2, Q_XA2}
+};
+
+struct s_Config {
+       char    ScanString[8];
+       SK_U32  Value;
+};
+
+static struct s_Config OemConfig = {
+       {'O','E','M','_','C','o','n','f'},
+#ifdef SK_OEM_CONFIG
+       OEM_CONFIG_VALUE,
+#else
+       0,
+#endif
+};
+
+/******************************************************************************
+ *
+ *     SkGePollTxD() - Enable / Disable Descriptor Polling of TxD Rings
+ *
+ * Description:
+ *     Enable or disable the descriptor polling of the transmit descriptor
+ *     ring(s) (TxD) for port 'Port'.
+ *     The new configuration is *not* saved over any SkGeStopPort() and
+ *     SkGeInitPort() calls.
+ *
+ * Returns:
+ *     nothing
+ */
+void SkGePollTxD(
+SK_AC  *pAC,           /* adapter context */
+SK_IOC IoC,            /* IO context */
+int            Port,           /* Port Index (MAC_1 + n) */
+SK_BOOL PollTxD)       /* SK_TRUE (enable pol.), SK_FALSE (disable pol.) */
+{
+       SK_GEPORT *pPrt;
+       SK_U32  DWord;
+
+       pPrt = &pAC->GIni.GP[Port];
+
+       DWord = (SK_U32)(PollTxD ? CSR_ENA_POL : CSR_DIS_POL);
+
+       if (pPrt->PXSQSize != 0) {
+               SK_OUT32(IoC, Q_ADDR(pPrt->PXsQOff, Q_CSR), DWord);
+       }
+       
+       if (pPrt->PXAQSize != 0) {
+               SK_OUT32(IoC, Q_ADDR(pPrt->PXaQOff, Q_CSR), DWord);
+       }
+}      /* SkGePollTxD */
+
+
+/******************************************************************************
+ *
+ *     SkGeYellowLED() - Switch the yellow LED on or off.
+ *
+ * Description:
+ *     Switch the yellow LED on or off.
+ *
+ * Note:
+ *     This function may be called any time after SkGeInit(Level 1).
+ *
+ * Returns:
+ *     nothing
+ */
+void SkGeYellowLED(
+SK_AC  *pAC,           /* adapter context */
+SK_IOC IoC,            /* IO context */
+int            State)          /* yellow LED state, 0 = OFF, 0 != ON */
+{
+       if (State == 0) {
+               /* Switch yellow LED OFF */
+               SK_OUT8(IoC, B0_LED, LED_STAT_OFF);
+       }
+       else {
+               /* Switch yellow LED ON */
+               SK_OUT8(IoC, B0_LED, LED_STAT_ON);
+       }
+}      /* SkGeYellowLED */
+
+
+#if (!defined(SK_SLIM) || defined(GENESIS))
+/******************************************************************************
+ *
+ *     SkGeXmitLED() - Modify the Operational Mode of a transmission LED.
+ *
+ * Description:
+ *     The Rx or Tx LED which is specified by 'Led' will be
+ *     enabled, disabled or switched on in test mode.
+ *
+ * Note:
+ *     'Led' must contain the address offset of the LEDs INI register.
+ *
+ * Usage:
+ *     SkGeXmitLED(pAC, IoC, MR_ADDR(Port, TX_LED_INI), SK_LED_ENA);
+ *
+ * Returns:
+ *     nothing
+ */
+void SkGeXmitLED(
+SK_AC  *pAC,           /* adapter context */
+SK_IOC IoC,            /* IO context */
+int            Led,            /* offset to the LED Init Value register */
+int            Mode)           /* Mode may be SK_LED_DIS, SK_LED_ENA, SK_LED_TST */
+{
+       SK_U32  LedIni;
+
+       switch (Mode) {
+       case SK_LED_ENA:
+               LedIni = SK_XMIT_DUR * (SK_U32)pAC->GIni.GIHstClkFact / 100;
+               SK_OUT32(IoC, Led + XMIT_LED_INI, LedIni);
+               SK_OUT8(IoC, Led + XMIT_LED_CTRL, LED_START);
+               break;
+       case SK_LED_TST:
+               SK_OUT8(IoC, Led + XMIT_LED_TST, LED_T_ON);
+               SK_OUT32(IoC, Led + XMIT_LED_CNT, 100);
+               SK_OUT8(IoC, Led + XMIT_LED_CTRL, LED_START);
+               break;
+       case SK_LED_DIS:
+       default:
+               /*
+                * Do NOT stop the LED Timer here. The LED might be
+                * in on state. But it needs to go off.
+                */
+               SK_OUT32(IoC, Led + XMIT_LED_CNT, 0);
+               SK_OUT8(IoC, Led + XMIT_LED_TST, LED_T_OFF);
+               break;
+       }
+                       
+       /*
+        * 1000BT: The Transmit LED is driven by the PHY.
+        * But the default LED configuration is used for
+        * Level One and Broadcom PHYs.
+        * (Broadcom: It may be that PHY_B_PEC_EN_LTR has to be set.)
+        * (In this case it has to be added here. But we will see. XXX)
+        */
+}      /* SkGeXmitLED */
+#endif /* !SK_SLIM || GENESIS */
+
+
+/******************************************************************************
+ *
+ *     DoCalcAddr() - Calculates the start and the end address of a queue.
+ *
+ * Description:
+ *     This function calculates the start and the end address of a queue.
+ *  Afterwards the 'StartVal' is incremented to the next start position.
+ *     If the port is already initialized the calculated values
+ *     will be checked against the configured values and an
+ *     error will be returned, if they are not equal.
+ *     If the port is not initialized the values will be written to
+ *     *StartAdr and *EndAddr.
+ *
+ * Returns:
+ *     0:      success
+ *     1:      configuration error
+ */
+static int DoCalcAddr(
+SK_AC          *pAC,                           /* adapter context */
+SK_GEPORT      SK_FAR *pPrt,           /* port index */
+int                    QuSize,                         /* size of the queue to configure in kB */
+SK_U32         SK_FAR *StartVal,       /* start value for address calculation */
+SK_U32         SK_FAR *QuStartAddr,/* start addr to calculate */
+SK_U32         SK_FAR *QuEndAddr)      /* end address to calculate */
+{
+       SK_U32  EndVal;
+       SK_U32  NextStart;
+       int             Rtv;
+
+       Rtv = 0;
+       if (QuSize == 0) {
+               EndVal = *StartVal;
+               NextStart = EndVal;
+       }
+       else {
+               EndVal = *StartVal + ((SK_U32)QuSize * 1024) - 1;
+               NextStart = EndVal + 1;
+       }
+
+       if (pPrt->PState >= SK_PRT_INIT) {
+               if (*StartVal != *QuStartAddr || EndVal != *QuEndAddr) {
+                       Rtv = 1;
+               }
+       }
+       else {
+               *QuStartAddr = *StartVal;
+               *QuEndAddr = EndVal;
+       }
+
+       *StartVal = NextStart;
+       return(Rtv);
+}      /* DoCalcAddr */
+
+/******************************************************************************
+ *
+ *     SkGeInitAssignRamToQueues() - allocate default queue sizes
+ *
+ * Description:
+ *     This function assigns the memory to the different queues and ports.
+ *     When DualNet is set to SK_TRUE all ports get the same amount of memory.
+ *  Otherwise the first port gets most of the memory and all the
+ *     other ports just the required minimum.
+ *     This function can only be called when pAC->GIni.GIRamSize and
+ *     pAC->GIni.GIMacsFound have been initialized, usually this happens
+ *     at init level 1
+ *
+ * Returns:
+ *     0 - ok
+ *     1 - invalid input values
+ *     2 - not enough memory
+ */
+
+int SkGeInitAssignRamToQueues(
+SK_AC  *pAC,                   /* Adapter context */
+int            ActivePort,             /* Active Port in RLMT mode */
+SK_BOOL        DualNet)                /* adapter context */
+{
+       int     i;
+       int     UsedKilobytes;                  /* memory already assigned */
+       int     ActivePortKilobytes;    /* memory available for active port */
+       SK_GEPORT *pGePort;
+
+       UsedKilobytes = 0;
+
+       if (ActivePort >= pAC->GIni.GIMacsFound) {
+               SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_INIT,
+                       ("SkGeInitAssignRamToQueues: ActivePort (%d) invalid\n",
+                       ActivePort));
+               return(1);
+       }
+       if (((pAC->GIni.GIMacsFound * (SK_MIN_RXQ_SIZE + SK_MIN_TXQ_SIZE)) +
+               ((RAM_QUOTA_SYNC == 0) ? 0 : SK_MIN_TXQ_SIZE)) > pAC->GIni.GIRamSize) {
+               SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_INIT,
+                       ("SkGeInitAssignRamToQueues: Not enough memory (%d)\n",
+                        pAC->GIni.GIRamSize));
+               return(2);
+       }
+
+       if (DualNet) {
+               /* every port gets the same amount of memory */
+               ActivePortKilobytes = pAC->GIni.GIRamSize / pAC->GIni.GIMacsFound;
+               for (i = 0; i < pAC->GIni.GIMacsFound; i++) {
+
+                       pGePort = &pAC->GIni.GP[i];
+                       
+                       /* take away the minimum memory for active queues */
+                       ActivePortKilobytes -= (SK_MIN_RXQ_SIZE + SK_MIN_TXQ_SIZE);
+
+                       /* receive queue gets the minimum + 80% of the rest */
+                       pGePort->PRxQSize = (int) (ROUND_QUEUE_SIZE_KB((
+                               ActivePortKilobytes * (unsigned long) RAM_QUOTA_RX) / 100))
+                               + SK_MIN_RXQ_SIZE;
+
+                       ActivePortKilobytes -= (pGePort->PRxQSize - SK_MIN_RXQ_SIZE);
+
+                       /* synchronous transmit queue */
+                       pGePort->PXSQSize = 0;
+
+                       /* asynchronous transmit queue */
+                       pGePort->PXAQSize = (int) ROUND_QUEUE_SIZE_KB(ActivePortKilobytes +
+                               SK_MIN_TXQ_SIZE);
+               }
+       }
+       else {  
+               /* Rlmt Mode or single link adapter */
+
+               /* Set standby queue size defaults for all standby ports */
+               for (i = 0; i < pAC->GIni.GIMacsFound; i++) {
+
+                       if (i != ActivePort) {
+                               pGePort = &pAC->GIni.GP[i];
+
+                               pGePort->PRxQSize = SK_MIN_RXQ_SIZE;
+                               pGePort->PXAQSize = SK_MIN_TXQ_SIZE;
+                               pGePort->PXSQSize = 0;
+
+                               /* Count used RAM */
+                               UsedKilobytes += pGePort->PRxQSize + pGePort->PXAQSize;
+                       }
+               }
+               /* what's left? */
+               ActivePortKilobytes = pAC->GIni.GIRamSize - UsedKilobytes;
+
+               /* assign it to the active port */
+               /* first take away the minimum memory */
+               ActivePortKilobytes -= (SK_MIN_RXQ_SIZE + SK_MIN_TXQ_SIZE);
+               pGePort = &pAC->GIni.GP[ActivePort];
+
+               /* receive queue get's the minimum + 80% of the rest */
+               pGePort->PRxQSize = (int) (ROUND_QUEUE_SIZE_KB((ActivePortKilobytes *
+                       (unsigned long) RAM_QUOTA_RX) / 100)) + SK_MIN_RXQ_SIZE;
+
+               ActivePortKilobytes -= (pGePort->PRxQSize - SK_MIN_RXQ_SIZE);
+
+               /* synchronous transmit queue */
+               pGePort->PXSQSize = 0;
+
+               /* asynchronous transmit queue */
+               pGePort->PXAQSize = (int) ROUND_QUEUE_SIZE_KB(ActivePortKilobytes) +
+                       SK_MIN_TXQ_SIZE;
+       }
+#ifdef VCPU
+       VCPUprintf(0, "PRxQSize=%u, PXSQSize=%u, PXAQSize=%u\n",
+               pGePort->PRxQSize, pGePort->PXSQSize, pGePort->PXAQSize);
+#endif /* VCPU */
+
+       return(0);
+}      /* SkGeInitAssignRamToQueues */
+
+/******************************************************************************
+ *
+ *     SkGeCheckQSize() - Checks the Adapters Queue Size Configuration
+ *
+ * Description:
+ *     This function verifies the Queue Size Configuration specified
+ *     in the variables PRxQSize, PXSQSize, and PXAQSize of all
+ *     used ports.
+ *     This requirements must be fullfilled to have a valid configuration:
+ *             - The size of all queues must not exceed GIRamSize.
+ *             - The queue sizes must be specified in units of 8 kB.
+ *             - The size of Rx queues of available ports must not be
+ *               smaller than 16 kB.
+ *             - The size of at least one Tx queue (synch. or asynch.)
+ *        of available ports must not be smaller than 16 kB
+ *        when Jumbo Frames are used.
+ *             - The RAM start and end addresses must not be changed
+ *               for ports which are already initialized.
+ *     Furthermore SkGeCheckQSize() defines the Start and End Addresses
+ *  of all ports and stores them into the HWAC port    structure.
+ *
+ * Returns:
+ *     0:      Queue Size Configuration valid
+ *     1:      Queue Size Configuration invalid
+ */
+static int SkGeCheckQSize(
+SK_AC   *pAC,          /* adapter context */
+int             Port)          /* port index */
+{
+       SK_GEPORT *pPrt;
+       int     i;
+       int     Rtv;
+       int     Rtv2;
+       SK_U32  StartAddr;
+#ifndef SK_SLIM
+       int     UsedMem;        /* total memory used (max. found ports) */
+#endif 
+
+       Rtv = 0;
+       
+#ifndef SK_SLIM
+
+       UsedMem = 0;
+       for (i = 0; i < pAC->GIni.GIMacsFound; i++) {
+               pPrt = &pAC->GIni.GP[i];
+
+               if ((pPrt->PRxQSize & QZ_UNITS) != 0 ||
+                       (pPrt->PXSQSize & QZ_UNITS) != 0 ||
+                       (pPrt->PXAQSize & QZ_UNITS) != 0) {
+
+                       SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E012, SKERR_HWI_E012MSG);
+                       return(1);
+               }
+
+               if (i == Port && pPrt->PRxQSize < SK_MIN_RXQ_SIZE) {
+                       SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E011, SKERR_HWI_E011MSG);
+                       return(1);
+               }
+               
+               /*
+                * the size of at least one Tx queue (synch. or asynch.) has to be > 0.
+                * if Jumbo Frames are used, this size has to be >= 16 kB.
+                */
+               if ((i == Port && pPrt->PXSQSize == 0 && pPrt->PXAQSize == 0) ||
+                       (pAC->GIni.GIPortUsage == SK_JUMBO_LINK &&
+            ((pPrt->PXSQSize > 0 && pPrt->PXSQSize < SK_MIN_TXQ_SIZE) ||
+                        (pPrt->PXAQSize > 0 && pPrt->PXAQSize < SK_MIN_TXQ_SIZE)))) {
+                               SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E023, SKERR_HWI_E023MSG);
+                               return(1);
+               }
+               
+               UsedMem += pPrt->PRxQSize + pPrt->PXSQSize + pPrt->PXAQSize;
+       }
+       
+       if (UsedMem > pAC->GIni.GIRamSize) {
+               SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E012, SKERR_HWI_E012MSG);
+               return(1);
+       }
+#endif /* !SK_SLIM */
+
+       /* Now start address calculation */
+       StartAddr = pAC->GIni.GIRamOffs;
+       for (i = 0; i < pAC->GIni.GIMacsFound; i++) {
+               pPrt = &pAC->GIni.GP[i];
+
+               /* Calculate/Check values for the receive queue */
+               Rtv2 = DoCalcAddr(pAC, pPrt, pPrt->PRxQSize, &StartAddr,
+                       &pPrt->PRxQRamStart, &pPrt->PRxQRamEnd);
+               Rtv |= Rtv2;
+
+               /* Calculate/Check values for the synchronous Tx queue */
+               Rtv2 = DoCalcAddr(pAC, pPrt, pPrt->PXSQSize, &StartAddr,
+                       &pPrt->PXsQRamStart, &pPrt->PXsQRamEnd);
+               Rtv |= Rtv2;
+
+               /* Calculate/Check values for the asynchronous Tx queue */
+               Rtv2 = DoCalcAddr(pAC, pPrt, pPrt->PXAQSize, &StartAddr,
+                       &pPrt->PXaQRamStart, &pPrt->PXaQRamEnd);
+               Rtv |= Rtv2;
+
+               if (Rtv) {
+                       SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E013, SKERR_HWI_E013MSG);
+                       return(1);
+               }
+       }
+
+       return(0);
+}      /* SkGeCheckQSize */
+
+
+#ifdef GENESIS
+/******************************************************************************
+ *
+ *     SkGeInitMacArb() - Initialize the MAC Arbiter
+ *
+ * Description:
+ *     This function initializes the MAC Arbiter.
+ *     It must not be called if there is still an
+ *     initialized or active port.
+ *
+ * Returns:
+ *     nothing
+ */
+static void SkGeInitMacArb(
+SK_AC  *pAC,           /* adapter context */
+SK_IOC IoC)            /* IO context */
+{
+       /* release local reset */
+       SK_OUT16(IoC, B3_MA_TO_CTRL, MA_RST_CLR);
+
+       /* configure timeout values */
+       SK_OUT8(IoC, B3_MA_TOINI_RX1, SK_MAC_TO_53);
+       SK_OUT8(IoC, B3_MA_TOINI_RX2, SK_MAC_TO_53);
+       SK_OUT8(IoC, B3_MA_TOINI_TX1, SK_MAC_TO_53);
+       SK_OUT8(IoC, B3_MA_TOINI_TX2, SK_MAC_TO_53);
+
+       SK_OUT8(IoC, B3_MA_RCINI_RX1, 0);
+       SK_OUT8(IoC, B3_MA_RCINI_RX2, 0);
+       SK_OUT8(IoC, B3_MA_RCINI_TX1, 0);
+       SK_OUT8(IoC, B3_MA_RCINI_TX2, 0);
+
+       /* recovery values are needed for XMAC II Rev. B2 only */
+       /* Fast Output Enable Mode was intended to use with Rev. B2, but now? */
+
+       /*
+        * There is no start or enable button to push, therefore
+        * the MAC arbiter is configured and enabled now.
+        */
+}      /* SkGeInitMacArb */
+
+
+/******************************************************************************
+ *
+ *     SkGeInitPktArb() - Initialize the Packet Arbiter
+ *
+ * Description:
+ *     This function initializes the Packet Arbiter.
+ *     It must not be called if there is still an
+ *     initialized or active port.
+ *
+ * Returns:
+ *     nothing
+ */
+static void SkGeInitPktArb(
+SK_AC  *pAC,           /* adapter context */
+SK_IOC IoC)            /* IO context */
+{
+       /* release local reset */
+       SK_OUT16(IoC, B3_PA_CTRL, PA_RST_CLR);
+
+       /* configure timeout values */
+       SK_OUT16(IoC, B3_PA_TOINI_RX1, SK_PKT_TO_MAX);
+       SK_OUT16(IoC, B3_PA_TOINI_RX2, SK_PKT_TO_MAX);
+       SK_OUT16(IoC, B3_PA_TOINI_TX1, SK_PKT_TO_MAX);
+       SK_OUT16(IoC, B3_PA_TOINI_TX2, SK_PKT_TO_MAX);
+
+       /*
+        * enable timeout timers if jumbo frames not used
+        * NOTE: the packet arbiter timeout interrupt is needed for
+        * half duplex hangup workaround
+        */
+       if (pAC->GIni.GIPortUsage != SK_JUMBO_LINK) {
+               if (pAC->GIni.GIMacsFound == 1) {
+                       SK_OUT16(IoC, B3_PA_CTRL, PA_ENA_TO_TX1);
+               }
+               else {
+                       SK_OUT16(IoC, B3_PA_CTRL, PA_ENA_TO_TX1 | PA_ENA_TO_TX2);
+               }
+       }
+}      /* SkGeInitPktArb */
+#endif /* GENESIS */
+
+
+/******************************************************************************
+ *
+ *     SkGeInitMacFifo() - Initialize the MAC FIFOs
+ *
+ * Description:
+ *     Initialize all MAC FIFOs of the specified port
+ *
+ * Returns:
+ *     nothing
+ */
+static void SkGeInitMacFifo(
+SK_AC  *pAC,           /* adapter context */
+SK_IOC IoC,            /* IO context */
+int            Port)           /* Port Index (MAC_1 + n) */
+{
+       SK_U16  Word;
+#ifdef VCPU
+       SK_U32  DWord;
+#endif /* VCPU */
+       /*
+        * For each FIFO:
+        *      - release local reset
+        *      - use default value for MAC FIFO size
+        *      - setup defaults for the control register
+        *      - enable the FIFO
+        */
+       
+#ifdef GENESIS
+       if (pAC->GIni.GIGenesis) {
+               /* Configure Rx MAC FIFO */
+               SK_OUT8(IoC, MR_ADDR(Port, RX_MFF_CTRL2), MFF_RST_CLR);
+               SK_OUT16(IoC, MR_ADDR(Port, RX_MFF_CTRL1), MFF_RX_CTRL_DEF);
+               SK_OUT8(IoC, MR_ADDR(Port, RX_MFF_CTRL2), MFF_ENA_OP_MD);
+       
+               /* Configure Tx MAC FIFO */
+               SK_OUT8(IoC, MR_ADDR(Port, TX_MFF_CTRL2), MFF_RST_CLR);
+               SK_OUT16(IoC, MR_ADDR(Port, TX_MFF_CTRL1), MFF_TX_CTRL_DEF);
+               SK_OUT8(IoC, MR_ADDR(Port, TX_MFF_CTRL2), MFF_ENA_OP_MD);
+       
+               /* Enable frame flushing if jumbo frames used */
+               if (pAC->GIni.GIPortUsage == SK_JUMBO_LINK) {
+                       SK_OUT16(IoC, MR_ADDR(Port, RX_MFF_CTRL1), MFF_ENA_FLUSH);
+               }
+       }
+#endif /* GENESIS */
+       
+#ifdef YUKON
+       if (pAC->GIni.GIYukon) {
+               /* set Rx GMAC FIFO Flush Mask */
+               SK_OUT16(IoC, MR_ADDR(Port, RX_GMF_FL_MSK), (SK_U16)RX_FF_FL_DEF_MSK);
+               
+               Word = (SK_U16)GMF_RX_CTRL_DEF;
+
+               /* disable Rx GMAC FIFO Flush for YUKON-Lite Rev. A0 only */
+               if (pAC->GIni.GIYukonLite && pAC->GIni.GIChipId == CHIP_ID_YUKON) {
+
+                       Word &= ~GMF_RX_F_FL_ON;
+               }
+               
+               /* Configure Rx MAC FIFO */
+               SK_OUT8(IoC, MR_ADDR(Port, RX_GMF_CTRL_T), (SK_U8)GMF_RST_CLR);
+               SK_OUT16(IoC, MR_ADDR(Port, RX_GMF_CTRL_T), Word);
+               
+               /* set Rx GMAC FIFO Flush Threshold (default: 0x0a -> 56 bytes) */
+               SK_OUT16(IoC, MR_ADDR(Port, RX_GMF_FL_THR), RX_GMF_FL_THR_DEF);
+               
+               /* Configure Tx MAC FIFO */
+               SK_OUT8(IoC, MR_ADDR(Port, TX_GMF_CTRL_T), (SK_U8)GMF_RST_CLR);
+               SK_OUT16(IoC, MR_ADDR(Port, TX_GMF_CTRL_T), (SK_U16)GMF_TX_CTRL_DEF);
+               
+#ifdef VCPU
+               SK_IN32(IoC, MR_ADDR(Port, RX_GMF_AF_THR), &DWord);
+               SK_IN32(IoC, MR_ADDR(Port, TX_GMF_AE_THR), &DWord);
+#endif /* VCPU */
+               
+               /* set Tx GMAC FIFO Almost Empty Threshold */
+/*             SK_OUT32(IoC, MR_ADDR(Port, TX_GMF_AE_THR), 0); */
+       }
+#endif /* YUKON */
+
+}      /* SkGeInitMacFifo */
+
+#ifdef SK_LNK_SYNC_CNT
+/******************************************************************************
+ *
+ *     SkGeLoadLnkSyncCnt() - Load the Link Sync Counter and starts counting
+ *
+ * Description:
+ *     This function starts the Link Sync Counter of the specified
+ *     port and enables the generation of an Link Sync IRQ.
+ *     The Link Sync Counter may be used to detect an active link,
+ *     if autonegotiation is not used.
+ *
+ * Note:
+ *     o To ensure receiving the Link Sync Event the LinkSyncCounter
+ *       should be initialized BEFORE clearing the XMAC's reset!
+ *     o Enable IS_LNK_SYNC_M1 and IS_LNK_SYNC_M2 after calling this
+ *       function.
+ *
+ * Returns:
+ *     nothing
+ */
+void SkGeLoadLnkSyncCnt(
+SK_AC  *pAC,           /* adapter context */
+SK_IOC IoC,            /* IO context */
+int            Port,           /* Port Index (MAC_1 + n) */
+SK_U32 CntVal)         /* Counter value */
+{
+       SK_U32  OrgIMsk;
+       SK_U32  NewIMsk;
+       SK_U32  ISrc;
+       SK_BOOL IrqPend;
+
+       /* stop counter */
+       SK_OUT8(IoC, MR_ADDR(Port, LNK_SYNC_CTRL), LED_STOP);
+
+       /*
+        * ASIC problem:
+        * Each time starting the Link Sync Counter an IRQ is generated
+        * by the adapter. See problem report entry from 21.07.98
+        *
+        * Workaround:  Disable Link Sync IRQ and clear the unexpeced IRQ
+        *              if no IRQ is already pending.
+        */
+       IrqPend = SK_FALSE;
+       SK_IN32(IoC, B0_ISRC, &ISrc);
+       SK_IN32(IoC, B0_IMSK, &OrgIMsk);
+       if (Port == MAC_1) {
+               NewIMsk = OrgIMsk & ~IS_LNK_SYNC_M1;
+               if ((ISrc & IS_LNK_SYNC_M1) != 0) {
+                       IrqPend = SK_TRUE;
+               }
+       }
+       else {
+               NewIMsk = OrgIMsk & ~IS_LNK_SYNC_M2;
+               if ((ISrc & IS_LNK_SYNC_M2) != 0) {
+                       IrqPend = SK_TRUE;
+               }
+       }
+       if (!IrqPend) {
+               SK_OUT32(IoC, B0_IMSK, NewIMsk);
+       }
+
+       /* load counter */
+       SK_OUT32(IoC, MR_ADDR(Port, LNK_SYNC_INI), CntVal);
+
+       /* start counter */
+       SK_OUT8(IoC, MR_ADDR(Port, LNK_SYNC_CTRL), LED_START);
+
+       if (!IrqPend) {
+               /* clear the unexpected IRQ, and restore the interrupt mask */
+               SK_OUT8(IoC, MR_ADDR(Port, LNK_SYNC_CTRL), LED_CLR_IRQ);
+               SK_OUT32(IoC, B0_IMSK, OrgIMsk);
+       }
+}      /* SkGeLoadLnkSyncCnt*/
+#endif /* SK_LNK_SYNC_CNT */
+
+#if defined(SK_DIAG) || defined(SK_CFG_SYNC)
+/******************************************************************************
+ *
+ *     SkGeCfgSync() - Configure synchronous bandwidth for this port.
+ *
+ * Description:
+ *     This function may be used to configure synchronous bandwidth
+ *     to the specified port. This may be done any time after
+ *     initializing the port. The configuration values are NOT saved
+ *     in the HWAC port structure and will be overwritten any
+ *     time when stopping and starting the port.
+ *     Any values for the synchronous configuration will be ignored
+ *     if the size of the synchronous queue is zero!
+ *
+ *     The default configuration for the synchronous service is
+ *     TXA_ENA_FSYNC. This means if the size of
+ *     the synchronous queue is unequal zero but no specific
+ *     synchronous bandwidth is configured, the synchronous queue
+ *     will always have the 'unlimited' transmit priority!
+ *
+ *     This mode will be restored if the synchronous bandwidth is
+ *     deallocated ('IntTime' = 0 and 'LimCount' = 0).
+ *
+ * Returns:
+ *     0:      success
+ *     1:      parameter configuration error
+ *     2:      try to configure quality of service although no
+ *             synchronous queue is configured
+ */
+int SkGeCfgSync(
+SK_AC  *pAC,           /* adapter context */
+SK_IOC IoC,            /* IO context */
+int            Port,           /* Port Index (MAC_1 + n) */
+SK_U32 IntTime,        /* Interval Timer Value in units of 8ns */
+SK_U32 LimCount,       /* Number of bytes to transfer during IntTime */
+int            SyncMode)       /* Sync Mode: TXA_ENA_ALLOC | TXA_DIS_ALLOC | 0 */
+{
+       int Rtv;
+
+       Rtv = 0;
+
+       /* check the parameters */
+       if (LimCount > IntTime ||
+               (LimCount == 0 && IntTime != 0) ||
+               (LimCount != 0 && IntTime == 0)) {
+
+               SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E010, SKERR_HWI_E010MSG);
+               return(1);
+       }
+       
+       if (pAC->GIni.GP[Port].PXSQSize == 0) {
+               SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E009, SKERR_HWI_E009MSG);
+               return(2);
+       }
+       
+       /* calculate register values */
+       IntTime = (IntTime / 2) * pAC->GIni.GIHstClkFact / 100;
+       LimCount = LimCount / 8;
+       
+       if (IntTime > TXA_MAX_VAL || LimCount > TXA_MAX_VAL) {
+               SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E010, SKERR_HWI_E010MSG);
+               return(1);
+       }
+
+       /*
+        * - Enable 'Force Sync' to ensure the synchronous queue
+        *   has the priority while configuring the new values.
+        * - Also 'disable alloc' to ensure the settings complies
+        *   to the SyncMode parameter.
+        * - Disable 'Rate Control' to configure the new values.
+        * - write IntTime and LimCount
+        * - start 'Rate Control' and disable 'Force Sync'
+        *   if Interval Timer or Limit Counter not zero.
+        */
+       SK_OUT8(IoC, MR_ADDR(Port, TXA_CTRL),
+               TXA_ENA_FSYNC | TXA_DIS_ALLOC | TXA_STOP_RC);
+       
+       SK_OUT32(IoC, MR_ADDR(Port, TXA_ITI_INI), IntTime);
+       SK_OUT32(IoC, MR_ADDR(Port, TXA_LIM_INI), LimCount);
+       
+       SK_OUT8(IoC, MR_ADDR(Port, TXA_CTRL),
+               (SK_U8)(SyncMode & (TXA_ENA_ALLOC | TXA_DIS_ALLOC)));
+       
+       if (IntTime != 0 || LimCount != 0) {
+               SK_OUT8(IoC, MR_ADDR(Port, TXA_CTRL), TXA_DIS_FSYNC | TXA_START_RC);
+       }
+
+       return(0);
+}      /* SkGeCfgSync */
+#endif /* SK_DIAG || SK_CFG_SYNC*/
+
+
+/******************************************************************************
+ *
+ *     DoInitRamQueue() - Initialize the RAM Buffer Address of a single Queue
+ *
+ * Desccription:
+ *     If the queue is used, enable and initialize it.
+ *     Make sure the queue is still reset, if it is not used.
+ *
+ * Returns:
+ *     nothing
+ */
+static void DoInitRamQueue(
+SK_AC  *pAC,                   /* adapter context */
+SK_IOC IoC,                    /* IO context */
+int            QuIoOffs,               /* Queue IO Address Offset */
+SK_U32 QuStartAddr,    /* Queue Start Address */
+SK_U32 QuEndAddr,              /* Queue End Address */
+int            QuType)                 /* Queue Type (SK_RX_SRAM_Q|SK_RX_BRAM_Q|SK_TX_RAM_Q) */
+{
+       SK_U32  RxUpThresVal;
+       SK_U32  RxLoThresVal;
+
+       if (QuStartAddr != QuEndAddr) {
+               /* calculate thresholds, assume we have a big Rx queue */
+               RxUpThresVal = (QuEndAddr + 1 - QuStartAddr - SK_RB_ULPP) / 8;
+               RxLoThresVal = (QuEndAddr + 1 - QuStartAddr - SK_RB_LLPP_B)/8;
+
+               /* build HW address format */
+               QuStartAddr = QuStartAddr / 8;
+               QuEndAddr = QuEndAddr / 8;
+
+               /* release local reset */
+               SK_OUT8(IoC, RB_ADDR(QuIoOffs, RB_CTRL), RB_RST_CLR);
+
+               /* configure addresses */
+               SK_OUT32(IoC, RB_ADDR(QuIoOffs, RB_START), QuStartAddr);
+               SK_OUT32(IoC, RB_ADDR(QuIoOffs, RB_END), QuEndAddr);
+               SK_OUT32(IoC, RB_ADDR(QuIoOffs, RB_WP), QuStartAddr);
+               SK_OUT32(IoC, RB_ADDR(QuIoOffs, RB_RP), QuStartAddr);
+
+               switch (QuType) {
+               case SK_RX_SRAM_Q:
+                       /* configure threshold for small Rx Queue */
+                       RxLoThresVal += (SK_RB_LLPP_B - SK_RB_LLPP_S) / 8;
+
+                       /* continue with SK_RX_BRAM_Q */
+               case SK_RX_BRAM_Q:
+                       /* write threshold for Rx Queue */
+
+                       SK_OUT32(IoC, RB_ADDR(QuIoOffs, RB_RX_UTPP), RxUpThresVal);
+                       SK_OUT32(IoC, RB_ADDR(QuIoOffs, RB_RX_LTPP), RxLoThresVal);
+
+                       /* the high priority threshold not used */
+                       break;
+               case SK_TX_RAM_Q:
+                       /*
+                        * Do NOT use Store & Forward under normal operation due to
+                        * performance optimization (GENESIS only).
+                        * But if Jumbo Frames are configured (XMAC Tx FIFO is only 4 kB)
+                        * or YUKON is used ((GMAC Tx FIFO is only 1 kB)
+                        * we NEED Store & Forward of the RAM buffer.
+                        */
+                       if (pAC->GIni.GIPortUsage == SK_JUMBO_LINK ||
+                               pAC->GIni.GIYukon) {
+                               /* enable Store & Forward Mode for the Tx Side */
+                               SK_OUT8(IoC, RB_ADDR(QuIoOffs, RB_CTRL), RB_ENA_STFWD);
+                       }
+                       break;
+               }
+
+               /* set queue operational */
+               SK_OUT8(IoC, RB_ADDR(QuIoOffs, RB_CTRL), RB_ENA_OP_MD);
+       }
+       else {
+               /* ensure the queue is still disabled */
+               SK_OUT8(IoC, RB_ADDR(QuIoOffs, RB_CTRL), RB_RST_SET);
+       }
+}      /* DoInitRamQueue */
+
+
+/******************************************************************************
+ *
+ *     SkGeInitRamBufs() - Initialize the RAM Buffer Queues
+ *
+ * Description:
+ *     Initialize all RAM Buffer Queues of the specified port
+ *
+ * Returns:
+ *     nothing
+ */
+static void SkGeInitRamBufs(
+SK_AC  *pAC,           /* adapter context */
+SK_IOC IoC,            /* IO context */
+int            Port)           /* Port Index (MAC_1 + n) */
+{
+       SK_GEPORT *pPrt;
+       int RxQType;
+
+       pPrt = &pAC->GIni.GP[Port];
+
+       if (pPrt->PRxQSize == SK_MIN_RXQ_SIZE) {
+               RxQType = SK_RX_SRAM_Q;         /* small Rx Queue */
+       }
+       else {
+               RxQType = SK_RX_BRAM_Q;         /* big Rx Queue */
+       }
+
+       DoInitRamQueue(pAC, IoC, pPrt->PRxQOff, pPrt->PRxQRamStart,
+               pPrt->PRxQRamEnd, RxQType);
+       
+       DoInitRamQueue(pAC, IoC, pPrt->PXsQOff, pPrt->PXsQRamStart,
+               pPrt->PXsQRamEnd, SK_TX_RAM_Q);
+       
+       DoInitRamQueue(pAC, IoC, pPrt->PXaQOff, pPrt->PXaQRamStart,
+               pPrt->PXaQRamEnd, SK_TX_RAM_Q);
+
+}      /* SkGeInitRamBufs */
+
+
+/******************************************************************************
+ *
+ *     SkGeInitRamIface() - Initialize the RAM Interface
+ *
+ * Description:
+ *     This function initializes the Adapters RAM Interface.
+ *
+ * Note:
+ *     This function is used in the diagnostics.
+ *
+ * Returns:
+ *     nothing
+ */
+static void SkGeInitRamIface(
+SK_AC  *pAC,           /* adapter context */
+SK_IOC IoC)            /* IO context */
+{
+       /* release local reset */
+       SK_OUT16(IoC, B3_RI_CTRL, RI_RST_CLR);
+
+       /* configure timeout values */
+       SK_OUT8(IoC, B3_RI_WTO_R1, SK_RI_TO_53);
+       SK_OUT8(IoC, B3_RI_WTO_XA1, SK_RI_TO_53);
+       SK_OUT8(IoC, B3_RI_WTO_XS1, SK_RI_TO_53);
+       SK_OUT8(IoC, B3_RI_RTO_R1, SK_RI_TO_53);
+       SK_OUT8(IoC, B3_RI_RTO_XA1, SK_RI_TO_53);
+       SK_OUT8(IoC, B3_RI_RTO_XS1, SK_RI_TO_53);
+       SK_OUT8(IoC, B3_RI_WTO_R2, SK_RI_TO_53);
+       SK_OUT8(IoC, B3_RI_WTO_XA2, SK_RI_TO_53);
+       SK_OUT8(IoC, B3_RI_WTO_XS2, SK_RI_TO_53);
+       SK_OUT8(IoC, B3_RI_RTO_R2, SK_RI_TO_53);
+       SK_OUT8(IoC, B3_RI_RTO_XA2, SK_RI_TO_53);
+       SK_OUT8(IoC, B3_RI_RTO_XS2, SK_RI_TO_53);
+
+}      /* SkGeInitRamIface */
+
+
+/******************************************************************************
+ *
+ *     SkGeInitBmu() - Initialize the BMU state machines
+ *
+ * Description:
+ *     Initialize all BMU state machines of the specified port
+ *
+ * Returns:
+ *     nothing
+ */
+static void SkGeInitBmu(
+SK_AC  *pAC,           /* adapter context */
+SK_IOC IoC,            /* IO context */
+int            Port)           /* Port Index (MAC_1 + n) */
+{
+       SK_GEPORT       *pPrt;
+       SK_U32          RxWm;
+       SK_U32          TxWm;
+
+       pPrt = &pAC->GIni.GP[Port];
+
+       RxWm = SK_BMU_RX_WM;
+       TxWm = SK_BMU_TX_WM;
+       
+       if (!pAC->GIni.GIPciSlot64 && !pAC->GIni.GIPciClock66) {
+               /* for better performance */
+               RxWm /= 2;
+               TxWm /= 2;
+       }
+
+       /* Rx Queue: Release all local resets and set the watermark */
+       SK_OUT32(IoC, Q_ADDR(pPrt->PRxQOff, Q_CSR), CSR_CLR_RESET);
+       SK_OUT32(IoC, Q_ADDR(pPrt->PRxQOff, Q_F), RxWm);
+
+       /*
+        * Tx Queue: Release all local resets if the queue is used !
+        *              set watermark
+        */
+       if (pPrt->PXSQSize != 0) {
+               SK_OUT32(IoC, Q_ADDR(pPrt->PXsQOff, Q_CSR), CSR_CLR_RESET);
+               SK_OUT32(IoC, Q_ADDR(pPrt->PXsQOff, Q_F), TxWm);
+       }
+       
+       if (pPrt->PXAQSize != 0) {
+               SK_OUT32(IoC, Q_ADDR(pPrt->PXaQOff, Q_CSR), CSR_CLR_RESET);
+               SK_OUT32(IoC, Q_ADDR(pPrt->PXaQOff, Q_F), TxWm);
+       }
+       /*
+        * Do NOT enable the descriptor poll timers here, because
+        * the descriptor addresses are not specified yet.
+        */
+}      /* SkGeInitBmu */
+
+
+/******************************************************************************
+ *
+ *     TestStopBit() - Test the stop bit of the queue
+ *
+ * Description:
+ *     Stopping a queue is not as simple as it seems to be.
+ *     If descriptor polling is enabled, it may happen
+ *     that RX/TX stop is done and SV idle is NOT set.
+ *     In this case we have to issue another stop command.
+ *
+ * Returns:
+ *     The queues control status register
+ */
+static SK_U32 TestStopBit(
+SK_AC  *pAC,           /* Adapter Context */
+SK_IOC IoC,            /* IO Context */
+int            QuIoOffs)       /* Queue IO Address Offset */
+{
+       SK_U32  QuCsr;  /* CSR contents */
+
+       SK_IN32(IoC, Q_ADDR(QuIoOffs, Q_CSR), &QuCsr);
+       
+       if ((QuCsr & (CSR_STOP | CSR_SV_IDLE)) == 0) {
+               /* Stop Descriptor overridden by start command */
+               SK_OUT32(IoC, Q_ADDR(QuIoOffs, Q_CSR), CSR_STOP);
+
+               SK_IN32(IoC, Q_ADDR(QuIoOffs, Q_CSR), &QuCsr);
+       }
+       
+       return(QuCsr);
+}      /* TestStopBit */
+
+
+/******************************************************************************
+ *
+ *     SkGeStopPort() - Stop the Rx/Tx activity of the port 'Port'.
+ *
+ * Description:
+ *     After calling this function the descriptor rings and Rx and Tx
+ *     queues of this port may be reconfigured.
+ *
+ *     It is possible to stop the receive and transmit path separate or
+ *     both together.
+ *
+ *     Dir =   SK_STOP_TX      Stops the transmit path only and resets the MAC.
+ *                             The receive queue is still active and
+ *                             the pending Rx frames may be still transferred
+ *                             into the RxD.
+ *             SK_STOP_RX      Stop the receive path. The tansmit path
+ *                             has to be stopped once before.
+ *             SK_STOP_ALL     SK_STOP_TX + SK_STOP_RX
+ *
+ *     RstMode = SK_SOFT_RST   Resets the MAC. The PHY is still alive.
+ *                     SK_HARD_RST     Resets the MAC and the PHY.
+ *
+ * Example:
+ *     1) A Link Down event was signaled for a port. Therefore the activity
+ *     of this port should be stopped and a hardware reset should be issued
+ *     to enable the workaround of XMAC Errata #2. But the received frames
+ *     should not be discarded.
+ *             ...
+ *             SkGeStopPort(pAC, IoC, Port, SK_STOP_TX, SK_HARD_RST);
+ *             (transfer all pending Rx frames)
+ *             SkGeStopPort(pAC, IoC, Port, SK_STOP_RX, SK_HARD_RST);
+ *             ...
+ *
+ *     2) An event was issued which request the driver to switch
+ *     the 'virtual active' link to an other already active port
+ *     as soon as possible. The frames in the receive queue of this
+ *     port may be lost. But the PHY must not be reset during this
+ *     event.
+ *             ...
+ *             SkGeStopPort(pAC, IoC, Port, SK_STOP_ALL, SK_SOFT_RST);
+ *             ...
+ *
+ * Extended Description:
+ *     If SK_STOP_TX is set,
+ *             o disable the MAC's receive and transmitter to prevent
+ *               from sending incomplete frames
+ *             o stop the port's transmit queues before terminating the
+ *               BMUs to prevent from performing incomplete PCI cycles
+ *               on the PCI bus
+ *             - The network Rx and Tx activity and PCI Tx transfer is
+ *               disabled now.
+ *             o reset the MAC depending on the RstMode
+ *             o Stop Interval Timer and Limit Counter of Tx Arbiter,
+ *               also disable Force Sync bit and Enable Alloc bit.
+ *             o perform a local reset of the port's Tx path
+ *                     - reset the PCI FIFO of the async Tx queue
+ *                     - reset the PCI FIFO of the sync Tx queue
+ *                     - reset the RAM Buffer async Tx queue
+ *                     - reset the RAM Buffer sync Tx queue
+ *                     - reset the MAC Tx FIFO
+ *             o switch Link and Tx LED off, stop the LED counters
+ *
+ *     If SK_STOP_RX is set,
+ *             o stop the port's receive queue
+ *             - The path data transfer activity is fully stopped now.
+ *             o perform a local reset of the port's Rx path
+ *                     - reset the PCI FIFO of the Rx queue
+ *                     - reset the RAM Buffer receive queue
+ *                     - reset the MAC Rx FIFO
+ *             o switch Rx LED off, stop the LED counter
+ *
+ *     If all ports are stopped,
+ *             o reset the RAM Interface.
+ *
+ * Notes:
+ *     o This function may be called during the driver states RESET_PORT and
+ *       SWITCH_PORT.
+ */
+void SkGeStopPort(
+SK_AC  *pAC,   /* adapter context */
+SK_IOC IoC,    /* I/O context */
+int            Port,   /* port to stop (MAC_1 + n) */
+int            Dir,    /* Direction to Stop (SK_STOP_RX, SK_STOP_TX, SK_STOP_ALL) */
+int            RstMode)/* Reset Mode (SK_SOFT_RST, SK_HARD_RST) */
+{
+#ifndef SK_DIAG
+       SK_EVPARA Para;
+#endif /* !SK_DIAG */
+       SK_GEPORT *pPrt;
+       SK_U32  DWord;
+       SK_U32  XsCsr;
+       SK_U32  XaCsr;
+       SK_U64  ToutStart;
+       int             i;
+       int             ToutCnt;
+
+       pPrt = &pAC->GIni.GP[Port];
+
+       if ((Dir & SK_STOP_TX) != 0) {
+               /* disable receiver and transmitter */
+               SkMacRxTxDisable(pAC, IoC, Port);
+               
+               /* stop both transmit queues */
+               /*
+                * If the BMU is in the reset state CSR_STOP will terminate
+                * immediately.
+                */
+               SK_OUT32(IoC, Q_ADDR(pPrt->PXsQOff, Q_CSR), CSR_STOP);
+               SK_OUT32(IoC, Q_ADDR(pPrt->PXaQOff, Q_CSR), CSR_STOP);
+
+               ToutStart = SkOsGetTime(pAC);
+               ToutCnt = 0;
+               do {
+                       /*
+                        * Clear packet arbiter timeout to make sure
+                        * this loop will terminate.
+                        */
+                       SK_OUT16(IoC, B3_PA_CTRL, (SK_U16)((Port == MAC_1) ?
+                               PA_CLR_TO_TX1 : PA_CLR_TO_TX2));
+
+                       /*
+                        * If the transfer stucks at the MAC the STOP command will not
+                        * terminate if we don't flush the XMAC's transmit FIFO !
+                        */
+                       SkMacFlushTxFifo(pAC, IoC, Port);
+
+                       XsCsr = TestStopBit(pAC, IoC, pPrt->PXsQOff);
+                       XaCsr = TestStopBit(pAC, IoC, pPrt->PXaQOff);
+
+                       if (SkOsGetTime(pAC) - ToutStart > (SK_TICKS_PER_SEC / 18)) {
+                               /*
+                                * Timeout of 1/18 second reached.
+                                * This needs to be checked at 1/18 sec only.
+                                */
+                               ToutCnt++;
+                               if (ToutCnt > 1) {
+                                       /* Might be a problem when the driver event handler
+                                        * calls StopPort again. XXX.
+                                        */
+
+                                       /* Fatal Error, Loop aborted */
+                                       SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_HWI_E018,
+                                               SKERR_HWI_E018MSG);
+#ifndef SK_DIAG
+                                       Para.Para64 = Port;
+                                       SkEventQueue(pAC, SKGE_DRV, SK_DRV_PORT_FAIL, Para);
+#endif /* !SK_DIAG */
+                                       return;
+                               }
+                               /*
+                                * Cache incoherency workaround: Assume a start command
+                                * has been lost while sending the frame.
+                                */
+                               ToutStart = SkOsGetTime(pAC);
+
+                               if ((XsCsr & CSR_STOP) != 0) {
+                                       SK_OUT32(IoC, Q_ADDR(pPrt->PXsQOff, Q_CSR), CSR_START);
+                               }
+                               if ((XaCsr & CSR_STOP) != 0) {
+                                       SK_OUT32(IoC, Q_ADDR(pPrt->PXaQOff, Q_CSR), CSR_START);
+                               }
+                       }
+
+                       /*
+                        * Because of the ASIC problem report entry from 21.08.1998 it is
+                        * required to wait until CSR_STOP is reset and CSR_SV_IDLE is set.
+                        */
+               } while ((XsCsr & (CSR_STOP | CSR_SV_IDLE)) != CSR_SV_IDLE ||
+                                (XaCsr & (CSR_STOP | CSR_SV_IDLE)) != CSR_SV_IDLE);
+
+               /* Reset the MAC depending on the RstMode */
+               if (RstMode == SK_SOFT_RST) {
+                       SkMacSoftRst(pAC, IoC, Port);
+               }
+               else {
+                       SkMacHardRst(pAC, IoC, Port);
+               }
+               
+               /* Disable Force Sync bit and Enable Alloc bit */
+               SK_OUT8(IoC, MR_ADDR(Port, TXA_CTRL),
+                       TXA_DIS_FSYNC | TXA_DIS_ALLOC | TXA_STOP_RC);
+               
+               /* Stop Interval Timer and Limit Counter of Tx Arbiter */
+               SK_OUT32(IoC, MR_ADDR(Port, TXA_ITI_INI), 0L);
+               SK_OUT32(IoC, MR_ADDR(Port, TXA_LIM_INI), 0L);
+
+               /* Perform a local reset of the port's Tx path */
+
+               /* Reset the PCI FIFO of the async Tx queue */
+               SK_OUT32(IoC, Q_ADDR(pPrt->PXaQOff, Q_CSR), CSR_SET_RESET);
+               /* Reset the PCI FIFO of the sync Tx queue */
+               SK_OUT32(IoC, Q_ADDR(pPrt->PXsQOff, Q_CSR), CSR_SET_RESET);
+               /* Reset the RAM Buffer async Tx queue */
+               SK_OUT8(IoC, RB_ADDR(pPrt->PXaQOff, RB_CTRL), RB_RST_SET);
+               /* Reset the RAM Buffer sync Tx queue */
+               SK_OUT8(IoC, RB_ADDR(pPrt->PXsQOff, RB_CTRL), RB_RST_SET);
+               
+               /* Reset Tx MAC FIFO */
+#ifdef GENESIS
+               if (pAC->GIni.GIGenesis) {
+                       /* Note: MFF_RST_SET does NOT reset the XMAC ! */
+                       SK_OUT8(IoC, MR_ADDR(Port, TX_MFF_CTRL2), MFF_RST_SET);
+
+                       /* switch Link and Tx LED off, stop the LED counters */
+                       /* Link LED is switched off by the RLMT and the Diag itself */
+                       SkGeXmitLED(pAC, IoC, MR_ADDR(Port, TX_LED_INI), SK_LED_DIS);
+               }
+#endif /* GENESIS */
+       
+#ifdef YUKON
+               if (pAC->GIni.GIYukon) {
+                       /* Reset TX MAC FIFO */
+                       SK_OUT8(IoC, MR_ADDR(Port, TX_GMF_CTRL_T), (SK_U8)GMF_RST_SET);
+               }
+#endif /* YUKON */
+       }
+
+       if ((Dir & SK_STOP_RX) != 0) {
+               /*
+                * The RX Stop Command will not terminate if no buffers
+                * are queued in the RxD ring. But it will always reach
+                * the Idle state. Therefore we can use this feature to
+                * stop the transfer of received packets.
+                */
+               /* stop the port's receive queue */
+               SK_OUT32(IoC, Q_ADDR(pPrt->PRxQOff, Q_CSR), CSR_STOP);
+               
+               i = 100;
+               do {
+                       /*
+                        * Clear packet arbiter timeout to make sure
+                        * this loop will terminate
+                        */
+                       SK_OUT16(IoC, B3_PA_CTRL, (SK_U16)((Port == MAC_1) ?
+                               PA_CLR_TO_RX1 : PA_CLR_TO_RX2));
+
+                       DWord = TestStopBit(pAC, IoC, pPrt->PRxQOff);
+
+                       /* timeout if i==0 (bug fix for #10748) */
+                       if (--i == 0) {
+                               SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_HWI_E024,
+                                       SKERR_HWI_E024MSG);
+                               break;
+                       }
+                       /*
+                        * because of the ASIC problem report entry from 21.08.98
+                        * it is required to wait until CSR_STOP is reset and
+                        * CSR_SV_IDLE is set.
+                        */
+               } while ((DWord & (CSR_STOP | CSR_SV_IDLE)) != CSR_SV_IDLE);
+
+               /* The path data transfer activity is fully stopped now */
+
+               /* Perform a local reset of the port's Rx path */
+
+                /*     Reset the PCI FIFO of the Rx queue */
+               SK_OUT32(IoC, Q_ADDR(pPrt->PRxQOff, Q_CSR), CSR_SET_RESET);
+               /* Reset the RAM Buffer receive queue */
+               SK_OUT8(IoC, RB_ADDR(pPrt->PRxQOff, RB_CTRL), RB_RST_SET);
+
+               /* Reset Rx MAC FIFO */
+#ifdef GENESIS
+               if (pAC->GIni.GIGenesis) {
+                       
+                       SK_OUT8(IoC, MR_ADDR(Port, RX_MFF_CTRL2), MFF_RST_SET);
+
+                       /* switch Rx LED off, stop the LED counter */
+                       SkGeXmitLED(pAC, IoC, MR_ADDR(Port, RX_LED_INI), SK_LED_DIS);
+               }
+#endif /* GENESIS */
+       
+#ifdef YUKON
+               if (pAC->GIni.GIYukon) {
+                       /* Reset Rx MAC FIFO */
+                       SK_OUT8(IoC, MR_ADDR(Port, RX_GMF_CTRL_T), (SK_U8)GMF_RST_SET);
+               }
+#endif /* YUKON */
+       }
+}      /* SkGeStopPort */
+
+
+/******************************************************************************
+ *
+ *     SkGeInit0() - Level 0 Initialization
+ *
+ * Description:
+ *     - Initialize the BMU address offsets
+ *
+ * Returns:
+ *     nothing
+ */
+static void SkGeInit0(
+SK_AC  *pAC,           /* adapter context */
+SK_IOC IoC)            /* IO context */
+{
+       int i;
+       SK_GEPORT *pPrt;
+
+       for (i = 0; i < SK_MAX_MACS; i++) {
+               pPrt = &pAC->GIni.GP[i];
+
+               pPrt->PState = SK_PRT_RESET;
+               pPrt->PRxQOff = QOffTab[i].RxQOff;
+               pPrt->PXsQOff = QOffTab[i].XsQOff;
+               pPrt->PXaQOff = QOffTab[i].XaQOff;
+               pPrt->PCheckPar = SK_FALSE;
+               pPrt->PIsave = 0;
+               pPrt->PPrevShorts = 0;
+               pPrt->PLinkResCt = 0;
+               pPrt->PAutoNegTOCt = 0;
+               pPrt->PPrevRx = 0;
+               pPrt->PPrevFcs = 0;
+               pPrt->PRxLim = SK_DEF_RX_WA_LIM;
+               pPrt->PLinkMode = (SK_U8)SK_LMODE_AUTOFULL;
+               pPrt->PLinkSpeedCap = (SK_U8)SK_LSPEED_CAP_1000MBPS;
+               pPrt->PLinkSpeed = (SK_U8)SK_LSPEED_1000MBPS;
+               pPrt->PLinkSpeedUsed = (SK_U8)SK_LSPEED_STAT_UNKNOWN;
+               pPrt->PLinkModeConf = (SK_U8)SK_LMODE_AUTOSENSE;
+               pPrt->PFlowCtrlMode = (SK_U8)SK_FLOW_MODE_SYM_OR_REM;
+               pPrt->PLinkCap = (SK_U8)(SK_LMODE_CAP_HALF | SK_LMODE_CAP_FULL |
+                       SK_LMODE_CAP_AUTOHALF | SK_LMODE_CAP_AUTOFULL);
+               pPrt->PLinkModeStatus = (SK_U8)SK_LMODE_STAT_UNKNOWN;
+               pPrt->PFlowCtrlCap = (SK_U8)SK_FLOW_MODE_SYM_OR_REM;
+               pPrt->PFlowCtrlStatus = (SK_U8)SK_FLOW_STAT_NONE;
+               pPrt->PMSCap = 0;
+               pPrt->PMSMode = (SK_U8)SK_MS_MODE_AUTO;
+               pPrt->PMSStatus = (SK_U8)SK_MS_STAT_UNSET;
+               pPrt->PLipaAutoNeg = (SK_U8)SK_LIPA_UNKNOWN;
+               pPrt->PAutoNegFail = SK_FALSE;
+               pPrt->PHWLinkUp = SK_FALSE;
+               pPrt->PLinkBroken = SK_TRUE; /* See WA code */
+               pPrt->PPhyPowerState = PHY_PM_OPERATIONAL_MODE;
+               pPrt->PMacColThres = TX_COL_DEF;
+               pPrt->PMacJamLen = TX_JAM_LEN_DEF;
+               pPrt->PMacJamIpgVal     = TX_JAM_IPG_DEF;
+               pPrt->PMacJamIpgData = TX_IPG_JAM_DEF;
+               pPrt->PMacIpgData = IPG_DATA_DEF;
+               pPrt->PMacLimit4 = SK_FALSE;
+       }
+
+       pAC->GIni.GIPortUsage = SK_RED_LINK;
+       pAC->GIni.GILedBlinkCtrl = (SK_U16)OemConfig.Value;
+       pAC->GIni.GIValIrqMask = IS_ALL_MSK;
+
+}      /* SkGeInit0*/
+
+
+/******************************************************************************
+ *
+ *     SkGeInit1() - Level 1 Initialization
+ *
+ * Description:
+ *     o Do a software reset.
+ *     o Clear all reset bits.
+ *     o Verify that the detected hardware is present.
+ *       Return an error if not.
+ *     o Get the hardware configuration
+ *             + Read the number of MACs/Ports.
+ *             + Read the RAM size.
+ *             + Read the PCI Revision Id.
+ *             + Find out the adapters host clock speed
+ *             + Read and check the PHY type
+ *
+ * Returns:
+ *     0:      success
+ *     5:      Unexpected PHY type detected
+ *     6:      HW self test failed
+ */
+static int SkGeInit1(
+SK_AC  *pAC,           /* adapter context */
+SK_IOC IoC)            /* IO context */
+{
+       SK_U8   Byte;
+       SK_U16  Word;
+       SK_U16  CtrlStat;
+       SK_U32  DWord;
+       int     RetVal;
+       int     i;
+
+       RetVal = 0;
+
+       /* save CLK_RUN bits (YUKON-Lite) */
+       SK_IN16(IoC, B0_CTST, &CtrlStat);
+
+       /* do the SW-reset */
+       SK_OUT8(IoC, B0_CTST, CS_RST_SET);
+
+       /* release the SW-reset */
+       SK_OUT8(IoC, B0_CTST, CS_RST_CLR);
+
+       /* reset all error bits in the PCI STATUS register */
+       /*
+        * Note: PCI Cfg cycles cannot be used, because they are not
+        *               available on some platforms after 'boot time'.
+        */
+       SK_IN16(IoC, PCI_C(PCI_STATUS), &Word);
+       
+       SK_OUT8(IoC, B2_TST_CTRL1, TST_CFG_WRITE_ON);
+       SK_OUT16(IoC, PCI_C(PCI_STATUS), (SK_U16)(Word | PCI_ERRBITS));
+       SK_OUT8(IoC, B2_TST_CTRL1, TST_CFG_WRITE_OFF);
+
+       /* release Master Reset */
+       SK_OUT8(IoC, B0_CTST, CS_MRST_CLR);
+
+#ifdef CLK_RUN
+       CtrlStat |= CS_CLK_RUN_ENA;
+#endif /* CLK_RUN */
+
+       /* restore CLK_RUN bits */
+       SK_OUT16(IoC, B0_CTST, (SK_U16)(CtrlStat &
+               (CS_CLK_RUN_HOT | CS_CLK_RUN_RST | CS_CLK_RUN_ENA)));
+
+       /* read Chip Identification Number */
+       SK_IN8(IoC, B2_CHIP_ID, &Byte);
+       pAC->GIni.GIChipId = Byte;
+       
+       /* read number of MACs */
+       SK_IN8(IoC, B2_MAC_CFG, &Byte);
+       pAC->GIni.GIMacsFound = (Byte & CFG_SNG_MAC) ? 1 : 2;
+       
+       /* get Chip Revision Number */
+       pAC->GIni.GIChipRev = (SK_U8)((Byte & CFG_CHIP_R_MSK) >> 4);
+
+       /* get diff. PCI parameters */
+       SK_IN16(IoC, B0_CTST, &CtrlStat);
+       
+       /* read the adapters RAM size */
+       SK_IN8(IoC, B2_E_0, &Byte);
+       
+       pAC->GIni.GIGenesis = SK_FALSE;
+       pAC->GIni.GIYukon = SK_FALSE;
+       pAC->GIni.GIYukonLite = SK_FALSE;
+
+#ifdef GENESIS
+       if (pAC->GIni.GIChipId == CHIP_ID_GENESIS) {
+
+               pAC->GIni.GIGenesis = SK_TRUE;
+
+               if (Byte == (SK_U8)3) {                                         
+                       /* special case: 4 x 64k x 36, offset = 0x80000 */
+                       pAC->GIni.GIRamSize = 1024;
+                       pAC->GIni.GIRamOffs = (SK_U32)512 * 1024;
+               }
+               else {
+                       pAC->GIni.GIRamSize = (int)Byte * 512;
+                       pAC->GIni.GIRamOffs = 0;
+               }
+               /* all GE adapters work with 53.125 MHz host clock */
+               pAC->GIni.GIHstClkFact = SK_FACT_53;
+               
+               /* set Descr. Poll Timer Init Value to 250 ms */
+               pAC->GIni.GIPollTimerVal =
+                       SK_DPOLL_DEF * (SK_U32)pAC->GIni.GIHstClkFact / 100;
+       }
+#endif /* GENESIS */
+       
+#ifdef YUKON
+       if (pAC->GIni.GIChipId != CHIP_ID_GENESIS) {
+               
+               pAC->GIni.GIYukon = SK_TRUE;
+               
+               pAC->GIni.GIRamSize = (Byte == (SK_U8)0) ? 128 : (int)Byte * 4;
+               
+               pAC->GIni.GIRamOffs = 0;
+               
+               /* WA for chip Rev. A */
+               pAC->GIni.GIWolOffs = (pAC->GIni.GIChipId == CHIP_ID_YUKON &&
+                       pAC->GIni.GIChipRev == 0) ? WOL_REG_OFFS : 0;
+               
+               /* get PM Capabilities of PCI config space */
+               SK_IN16(IoC, PCI_C(PCI_PM_CAP_REG), &Word);
+
+               /* check if VAUX is available */
+               if (((CtrlStat & CS_VAUX_AVAIL) != 0) &&
+                       /* check also if PME from D3cold is set */
+                       ((Word & PCI_PME_D3C_SUP) != 0)) {
+                       /* set entry in GE init struct */
+                       pAC->GIni.GIVauxAvail = SK_TRUE;
+               }
+               
+               if (pAC->GIni.GIChipId == CHIP_ID_YUKON_LITE) {
+                       /* this is Rev. A1 */
+                       pAC->GIni.GIYukonLite = SK_TRUE;
+               }
+               else {
+                       /* save Flash-Address Register */
+                       SK_IN32(IoC, B2_FAR, &DWord);
+
+                       /* test Flash-Address Register */
+                       SK_OUT8(IoC, B2_FAR + 3, 0xff);
+                       SK_IN8(IoC, B2_FAR + 3, &Byte);
+
+                       if (Byte != 0) {
+                               /* this is Rev. A0 */
+                               pAC->GIni.GIYukonLite = SK_TRUE;
+
+                               /* restore Flash-Address Register */
+                               SK_OUT32(IoC, B2_FAR, DWord);
+                       }
+               }
+
+               /* switch power to VCC (WA for VAUX problem) */
+               SK_OUT8(IoC, B0_POWER_CTRL, (SK_U8)(PC_VAUX_ENA | PC_VCC_ENA |
+                       PC_VAUX_OFF | PC_VCC_ON));
+
+               /* read the Interrupt source */
+               SK_IN32(IoC, B0_ISRC, &DWord);
+               
+               if ((DWord & IS_HW_ERR) != 0) {
+                       /* read the HW Error Interrupt source */
+                       SK_IN32(IoC, B0_HWE_ISRC, &DWord);
+                       
+                       if ((DWord & IS_IRQ_SENSOR) != 0) {
+                               /* disable HW Error IRQ */
+                               pAC->GIni.GIValIrqMask &= ~IS_HW_ERR;
+                       }
+               }
+               
+               for (i = 0; i < pAC->GIni.GIMacsFound; i++) {
+                       /* set GMAC Link Control reset */
+                       SK_OUT16(IoC, MR_ADDR(i, GMAC_LINK_CTRL), GMLC_RST_SET);
+
+                       /* clear GMAC Link Control reset */
+                       SK_OUT16(IoC, MR_ADDR(i, GMAC_LINK_CTRL), GMLC_RST_CLR);
+               }
+               /* all YU chips work with 78.125 MHz host clock */
+               pAC->GIni.GIHstClkFact = SK_FACT_78;
+               
+               pAC->GIni.GIPollTimerVal = SK_DPOLL_MAX;        /* 215 ms */
+       }
+#endif /* YUKON */
+
+       /* check if 64-bit PCI Slot is present */
+       pAC->GIni.GIPciSlot64 = (SK_BOOL)((CtrlStat & CS_BUS_SLOT_SZ) != 0);
+       
+       /* check if 66 MHz PCI Clock is active */
+       pAC->GIni.GIPciClock66 = (SK_BOOL)((CtrlStat & CS_BUS_CLOCK) != 0);
+
+       /* read PCI HW Revision Id. */
+       SK_IN8(IoC, PCI_C(PCI_REV_ID), &Byte);
+       pAC->GIni.GIPciHwRev = Byte;
+
+       /* read the PMD type */
+       SK_IN8(IoC, B2_PMD_TYP, &Byte);
+       pAC->GIni.GICopperType = (SK_U8)(Byte == 'T');
+
+       /* read the PHY type */
+       SK_IN8(IoC, B2_E_1, &Byte);
+
+       Byte &= 0x0f;   /* the PHY type is stored in the lower nibble */
+       for (i = 0; i < pAC->GIni.GIMacsFound; i++) {
+               
+#ifdef GENESIS
+               if (pAC->GIni.GIGenesis) {
+                       switch (Byte) {
+                       case SK_PHY_XMAC:
+                               pAC->GIni.GP[i].PhyAddr = PHY_ADDR_XMAC;
+                               break;
+                       case SK_PHY_BCOM:
+                               pAC->GIni.GP[i].PhyAddr = PHY_ADDR_BCOM;
+                               pAC->GIni.GP[i].PMSCap = (SK_U8)(SK_MS_CAP_AUTO |
+                                       SK_MS_CAP_MASTER | SK_MS_CAP_SLAVE);
+                               break;
+#ifdef OTHER_PHY
+                       case SK_PHY_LONE:
+                               pAC->GIni.GP[i].PhyAddr = PHY_ADDR_LONE;
+                               break;
+                       case SK_PHY_NAT:
+                               pAC->GIni.GP[i].PhyAddr = PHY_ADDR_NAT;
+                               break;
+#endif /* OTHER_PHY */
+                       default:
+                               /* ERROR: unexpected PHY type detected */
+                               RetVal = 5;
+                               break;
+                       }
+               }
+#endif /* GENESIS */
+       
+#ifdef YUKON
+               if (pAC->GIni.GIYukon) {
+                       
+                       if (Byte < (SK_U8)SK_PHY_MARV_COPPER) {
+                               /* if this field is not initialized */
+                               Byte = (SK_U8)SK_PHY_MARV_COPPER;
+                               
+                               pAC->GIni.GICopperType = SK_TRUE;
+                       }
+                       
+                       pAC->GIni.GP[i].PhyAddr = PHY_ADDR_MARV;
+                       
+                       if (pAC->GIni.GICopperType) {
+
+                               pAC->GIni.GP[i].PLinkSpeedCap = (SK_U8)(SK_LSPEED_CAP_AUTO |
+                                       SK_LSPEED_CAP_10MBPS | SK_LSPEED_CAP_100MBPS |
+                                       SK_LSPEED_CAP_1000MBPS);
+                               
+                               pAC->GIni.GP[i].PLinkSpeed = (SK_U8)SK_LSPEED_AUTO;
+                               
+                               pAC->GIni.GP[i].PMSCap = (SK_U8)(SK_MS_CAP_AUTO |
+                                       SK_MS_CAP_MASTER | SK_MS_CAP_SLAVE);
+                       }
+                       else {
+                               Byte = (SK_U8)SK_PHY_MARV_FIBER;
+                       }
+               }
+#endif /* YUKON */
+               
+               pAC->GIni.GP[i].PhyType = (int)Byte;
+               
+               SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_INIT,
+                       ("PHY type: %d  PHY addr: %04x\n", Byte,
+                       pAC->GIni.GP[i].PhyAddr));
+       }
+       
+       /* get MAC Type & set function pointers dependent on */
+#ifdef GENESIS
+       if (pAC->GIni.GIGenesis) {
+               
+               pAC->GIni.GIMacType = SK_MAC_XMAC;
+
+               pAC->GIni.GIFunc.pFnMacUpdateStats      = SkXmUpdateStats;
+               pAC->GIni.GIFunc.pFnMacStatistic        = SkXmMacStatistic;
+               pAC->GIni.GIFunc.pFnMacResetCounter     = SkXmResetCounter;
+               pAC->GIni.GIFunc.pFnMacOverflow         = SkXmOverflowStatus;
+       }
+#endif /* GENESIS */
+       
+#ifdef YUKON
+       if (pAC->GIni.GIYukon) {
+               
+               pAC->GIni.GIMacType = SK_MAC_GMAC;
+
+               pAC->GIni.GIFunc.pFnMacUpdateStats      = SkGmUpdateStats;
+               pAC->GIni.GIFunc.pFnMacStatistic        = SkGmMacStatistic;
+               pAC->GIni.GIFunc.pFnMacResetCounter     = SkGmResetCounter;
+               pAC->GIni.GIFunc.pFnMacOverflow         = SkGmOverflowStatus;
+
+#ifdef SPECIAL_HANDLING
+               if (pAC->GIni.GIChipId == CHIP_ID_YUKON) {
+                       /* check HW self test result */
+                       SK_IN8(IoC, B2_E_3, &Byte);
+                       if (Byte & B2_E3_RES_MASK) {
+                               RetVal = 6;
+                       }
+               }
+#endif
+       }
+#endif /* YUKON */
+       
+       return(RetVal);
+}      /* SkGeInit1 */
+
+
+/******************************************************************************
+ *
+ *     SkGeInit2() - Level 2 Initialization
+ *
+ * Description:
+ *     - start the Blink Source Counter
+ *     - start the Descriptor Poll Timer
+ *     - configure the MAC-Arbiter
+ *     - configure the Packet-Arbiter
+ *     - enable the Tx Arbiters
+ *     - enable the RAM Interface Arbiter
+ *
+ * Returns:
+ *     nothing
+ */
+static void SkGeInit2(
+SK_AC  *pAC,           /* adapter context */
+SK_IOC IoC)            /* IO context */
+{
+#ifdef GENESIS
+       SK_U32  DWord;
+#endif /* GENESIS */
+       int             i;
+
+       /* start the Descriptor Poll Timer */
+       if (pAC->GIni.GIPollTimerVal != 0) {
+               if (pAC->GIni.GIPollTimerVal > SK_DPOLL_MAX) {
+                       pAC->GIni.GIPollTimerVal = SK_DPOLL_MAX;
+
+                       SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E017, SKERR_HWI_E017MSG);
+               }
+               SK_OUT32(IoC, B28_DPT_INI, pAC->GIni.GIPollTimerVal);
+               SK_OUT8(IoC, B28_DPT_CTRL, DPT_START);
+       }
+
+#ifdef GENESIS
+       if (pAC->GIni.GIGenesis) {
+               /* start the Blink Source Counter */
+               DWord = SK_BLK_DUR * (SK_U32)pAC->GIni.GIHstClkFact / 100;
+
+               SK_OUT32(IoC, B2_BSC_INI, DWord);
+               SK_OUT8(IoC, B2_BSC_CTRL, BSC_START);
+
+               /*
+                * Configure the MAC Arbiter and the Packet Arbiter.
+                * They will be started once and never be stopped.
+                */
+               SkGeInitMacArb(pAC, IoC);
+
+               SkGeInitPktArb(pAC, IoC);
+       }
+#endif /* GENESIS */
+       
+#ifdef YUKON
+       if (pAC->GIni.GIYukon) {
+               /* start Time Stamp Timer */
+               SK_OUT8(IoC, GMAC_TI_ST_CTRL, (SK_U8)GMT_ST_START);
+       }
+#endif /* YUKON */
+
+       /* enable the Tx Arbiters */
+       for (i = 0; i < pAC->GIni.GIMacsFound; i++) {
+               SK_OUT8(IoC, MR_ADDR(i, TXA_CTRL), TXA_ENA_ARB);
+       }
+
+       /* enable the RAM Interface Arbiter */
+       SkGeInitRamIface(pAC, IoC);
+
+}      /* SkGeInit2 */
+
+/******************************************************************************
+ *
+ *     SkGeInit() - Initialize the GE Adapter with the specified level.
+ *
+ * Description:
+ *     Level   0:      Initialize the Module structures.
+ *     Level   1:      Generic Hardware Initialization. The IOP/MemBase pointer has
+ *                             to be set before calling this level.
+ *
+ *                     o Do a software reset.
+ *                     o Clear all reset bits.
+ *                     o Verify that the detected hardware is present.
+ *                       Return an error if not.
+ *                     o Get the hardware configuration
+ *                             + Set GIMacsFound with the number of MACs.
+ *                             + Store the RAM size in GIRamSize.
+ *                             + Save the PCI Revision ID in GIPciHwRev.
+ *                     o return an error
+ *                             if Number of MACs > SK_MAX_MACS
+ *
+ *                     After returning from Level 0 the adapter
+ *                     may be accessed with IO operations.
+ *
+ *     Level   2:      start the Blink Source Counter
+ *
+ * Returns:
+ *     0:      success
+ *     1:      Number of MACs exceeds SK_MAX_MACS      (after level 1)
+ *     2:      Adapter not present or not accessible
+ *     3:      Illegal initialization level
+ *     4:      Initialization Level 1 Call missing
+ *     5:      Unexpected PHY type detected
+ *     6:      HW self test failed
+ */
+int    SkGeInit(
+SK_AC  *pAC,           /* adapter context */
+SK_IOC IoC,            /* IO context */
+int            Level)          /* initialization level */
+{
+       int             RetVal;         /* return value */
+       SK_U32  DWord;
+
+       RetVal = 0;
+       SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_INIT,
+               ("SkGeInit(Level %d)\n", Level));
+
+       switch (Level) {
+       case SK_INIT_DATA:
+               /* Initialization Level 0 */
+               SkGeInit0(pAC, IoC);
+               pAC->GIni.GILevel = SK_INIT_DATA;
+               break;
+       
+       case SK_INIT_IO:
+               /* Initialization Level 1 */
+               RetVal = SkGeInit1(pAC, IoC);
+               if (RetVal != 0) {
+                       break;
+               }
+
+               /* check if the adapter seems to be accessible */
+               SK_OUT32(IoC, B2_IRQM_INI, SK_TEST_VAL);
+               SK_IN32(IoC, B2_IRQM_INI, &DWord);
+               SK_OUT32(IoC, B2_IRQM_INI, 0L);
+               
+               if (DWord != SK_TEST_VAL) {
+                       RetVal = 2;
+                       break;
+               }
+
+               /* check if the number of GIMacsFound matches SK_MAX_MACS */
+               if (pAC->GIni.GIMacsFound > SK_MAX_MACS) {
+                       RetVal = 1;
+                       break;
+               }
+
+               /* Level 1 successfully passed */
+               pAC->GIni.GILevel = SK_INIT_IO;
+               break;
+       
+       case SK_INIT_RUN:
+               /* Initialization Level 2 */
+               if (pAC->GIni.GILevel != SK_INIT_IO) {
+#ifndef SK_DIAG
+                       SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E002, SKERR_HWI_E002MSG);
+#endif /* !SK_DIAG */
+                       RetVal = 4;
+                       break;
+               }
+               SkGeInit2(pAC, IoC);
+
+               /* Level 2 successfully passed */
+               pAC->GIni.GILevel = SK_INIT_RUN;
+               break;
+       
+       default:
+               SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E003, SKERR_HWI_E003MSG);
+               RetVal = 3;
+               break;
+       }
+
+       return(RetVal);
+}      /* SkGeInit */
+
+
+/******************************************************************************
+ *
+ *     SkGeDeInit() - Deinitialize the adapter
+ *
+ * Description:
+ *     All ports of the adapter will be stopped if not already done.
+ *     Do a software reset and switch off all LEDs.
+ *
+ * Returns:
+ *     nothing
+ */
+void SkGeDeInit(
+SK_AC  *pAC,           /* adapter context */
+SK_IOC IoC)            /* IO context */
+{
+       int     i;
+       SK_U16  Word;
+
+#if (!defined(SK_SLIM) && !defined(VCPU))
+       /* ensure I2C is ready */
+       SkI2cWaitIrq(pAC, IoC);
+#endif 
+
+       /* stop all current transfer activity */
+       for (i = 0; i < pAC->GIni.GIMacsFound; i++) {
+               if (pAC->GIni.GP[i].PState != SK_PRT_STOP &&
+                       pAC->GIni.GP[i].PState != SK_PRT_RESET) {
+
+                       SkGeStopPort(pAC, IoC, i, SK_STOP_ALL, SK_HARD_RST);
+               }
+       }
+
+       /* Reset all bits in the PCI STATUS register */
+       /*
+        * Note: PCI Cfg cycles cannot be used, because they are not
+        *       available on some platforms after 'boot time'.
+        */
+       SK_IN16(IoC, PCI_C(PCI_STATUS), &Word);
+       
+       SK_OUT8(IoC, B2_TST_CTRL1, TST_CFG_WRITE_ON);
+       SK_OUT16(IoC, PCI_C(PCI_STATUS), (SK_U16)(Word | PCI_ERRBITS));
+       SK_OUT8(IoC, B2_TST_CTRL1, TST_CFG_WRITE_OFF);
+
+       /* do the reset, all LEDs are switched off now */
+       SK_OUT8(IoC, B0_CTST, CS_RST_SET);
+       
+       pAC->GIni.GILevel = SK_INIT_DATA;
+}      /* SkGeDeInit */
+
+
+/******************************************************************************
+ *
+ *     SkGeInitPort()  Initialize the specified port.
+ *
+ * Description:
+ *     PRxQSize, PXSQSize, and PXAQSize has to be
+ *     configured for the specified port before calling this function.
+ *  The descriptor rings has to be initialized too.
+ *
+ *     o (Re)configure queues of the specified port.
+ *     o configure the MAC of the specified port.
+ *     o put ASIC and MAC(s) in operational mode.
+ *     o initialize Rx/Tx and Sync LED
+ *     o initialize RAM Buffers and MAC FIFOs
+ *
+ *     The port is ready to connect when returning.
+ *
+ * Note:
+ *     The MAC's Rx and Tx state machine is still disabled when returning.
+ *
+ * Returns:
+ *     0:      success
+ *     1:      Queue size initialization error. The configured values
+ *             for PRxQSize, PXSQSize, or PXAQSize are invalid for one
+ *             or more queues. The specified port was NOT initialized.
+ *             An error log entry was generated.
+ *     2:      The port has to be stopped before it can be initialized again.
+ */
+int SkGeInitPort(
+SK_AC  *pAC,           /* adapter context */
+SK_IOC IoC,            /* IO context */
+int            Port)           /* Port to configure */
+{
+       SK_GEPORT *pPrt;
+
+       pPrt = &pAC->GIni.GP[Port];
+
+       if (SkGeCheckQSize(pAC, Port) != 0) {
+               SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E004, SKERR_HWI_E004MSG);
+               return(1);
+       }
+       
+       if (pPrt->PState == SK_PRT_INIT || pPrt->PState == SK_PRT_RUN) {
+               SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E005, SKERR_HWI_E005MSG);
+               return(2);
+       }
+
+       /* configuration ok, initialize the Port now */
+
+#ifdef GENESIS
+       if (pAC->GIni.GIGenesis) {
+               /* initialize Rx, Tx and Link LED */
+               /*
+                * If 1000BT Phy needs LED initialization than swap
+                * LED and XMAC initialization order
+                */
+               SkGeXmitLED(pAC, IoC, MR_ADDR(Port, TX_LED_INI), SK_LED_ENA);
+               SkGeXmitLED(pAC, IoC, MR_ADDR(Port, RX_LED_INI), SK_LED_ENA);
+               /* The Link LED is initialized by RLMT or Diagnostics itself */
+               
+               SkXmInitMac(pAC, IoC, Port);
+       }
+#endif /* GENESIS */
+       
+#ifdef YUKON
+       if (pAC->GIni.GIYukon) {
+
+               SkGmInitMac(pAC, IoC, Port);
+       }
+#endif /* YUKON */
+       
+       /* do NOT initialize the Link Sync Counter */
+
+       SkGeInitMacFifo(pAC, IoC, Port);
+       
+       SkGeInitRamBufs(pAC, IoC, Port);
+       
+       if (pPrt->PXSQSize != 0) {
+               /* enable Force Sync bit if synchronous queue available */
+               SK_OUT8(IoC, MR_ADDR(Port, TXA_CTRL), TXA_ENA_FSYNC);
+       }
+       
+       SkGeInitBmu(pAC, IoC, Port);
+
+       /* mark port as initialized */
+       pPrt->PState = SK_PRT_INIT;
+
+       return(0);
+}      /* SkGeInitPort */
diff --git a/drivers/net/sk98lin/skgemib.c b/drivers/net/sk98lin/skgemib.c
new file mode 100644 (file)
index 0000000..0a6f67a
--- /dev/null
@@ -0,0 +1,1075 @@
+/*****************************************************************************
+ *
+ * Name:       skgemib.c
+ * Project:    GEnesis, PCI Gigabit Ethernet Adapter
+ * Version:    $Revision: 1.11 $
+ * Date:       $Date: 2003/09/15 13:38:12 $
+ * Purpose:    Private Network Management Interface Management Database
+ *
+ ****************************************************************************/
+
+/******************************************************************************
+ *
+ *     (C)Copyright 1998-2002 SysKonnect GmbH.
+ *     (C)Copyright 2002-2003 Marvell.
+ *
+ *     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.
+ *
+ *     The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/*
+ * PRIVATE OID handler function prototypes
+ */
+PNMI_STATIC int Addr(SK_AC *pAC, SK_IOC IoC, int action,
+       SK_U32 Id, char *pBuf, unsigned int *pLen, SK_U32 Instance,
+       unsigned int TableIndex, SK_U32 NetIndex);
+PNMI_STATIC int CsumStat(SK_AC *pAC, SK_IOC IoC, int action, SK_U32 Id,
+       char *pBuf, unsigned int *pLen, SK_U32 Instance,
+       unsigned int TableIndex, SK_U32 NetIndex);
+PNMI_STATIC int General(SK_AC *pAC, SK_IOC IoC, int action, SK_U32 Id,
+       char *pBuf, unsigned int *pLen, SK_U32 Instance,
+       unsigned int TableIndex, SK_U32 NetIndex);
+PNMI_STATIC int Mac8023Stat(SK_AC *pAC, SK_IOC IoC, int action, SK_U32 Id,
+       char *pBuf, unsigned int *pLen, SK_U32 Instance,
+       unsigned int TableIndex, SK_U32 NetIndex);
+PNMI_STATIC int MacPrivateConf(SK_AC *pAC, SK_IOC IoC, int action, SK_U32 Id,
+       char *pBuf, unsigned int *pLen, SK_U32 Instance,
+       unsigned int TableIndex, SK_U32 NetIndex);
+PNMI_STATIC int MacPrivateStat(SK_AC *pAC, SK_IOC IoC, int action, SK_U32 Id,
+       char *pBuf, unsigned int *pLen, SK_U32 Instance,
+       unsigned int TableIndex, SK_U32 NetIndex);
+PNMI_STATIC int Monitor(SK_AC *pAC, SK_IOC IoC, int action,
+       SK_U32 Id, char *pBuf, unsigned int *pLen, SK_U32 Instance,
+       unsigned int TableIndex, SK_U32 NetIndex);
+PNMI_STATIC int OidStruct(SK_AC *pAC, SK_IOC IoC, int action, SK_U32 Id,
+       char *pBuf, unsigned int *pLen, SK_U32 Instance,
+       unsigned int TableIndex, SK_U32 NetIndex);
+PNMI_STATIC int Perform(SK_AC *pAC, SK_IOC IoC, int action, SK_U32 Id,
+       char *pBuf, unsigned int* pLen, SK_U32 Instance,
+       unsigned int TableIndex, SK_U32 NetIndex);
+PNMI_STATIC int Rlmt(SK_AC *pAC, SK_IOC IoC, int action, SK_U32 Id,
+       char *pBuf, unsigned int *pLen, SK_U32 Instance,
+       unsigned int TableIndex, SK_U32 NetIndex);
+PNMI_STATIC int RlmtStat(SK_AC *pAC, SK_IOC IoC, int action, SK_U32 Id,
+       char *pBuf, unsigned int *pLen, SK_U32 Instance,
+       unsigned int TableIndex, SK_U32 NetIndex);
+PNMI_STATIC int SensorStat(SK_AC *pAC, SK_IOC IoC, int action, SK_U32 Id,
+       char *pBuf, unsigned int *pLen, SK_U32 Instance,
+       unsigned int TableIndex, SK_U32 NetIndex);
+PNMI_STATIC int Vpd(SK_AC *pAC, SK_IOC IoC, int action, SK_U32 Id,
+       char *pBuf, unsigned int *pLen, SK_U32 Instance,
+       unsigned int TableIndex, SK_U32 NetIndex);
+PNMI_STATIC int Vct(SK_AC *pAC, SK_IOC IoC, int action, SK_U32 Id,
+       char *pBuf, unsigned int *pLen, SK_U32 Instance,
+       unsigned int TableIndex, SK_U32 NetIndex);
+
+#ifdef SK_POWER_MGMT
+PNMI_STATIC int PowerManagement(SK_AC *pAC, SK_IOC IoC, int action, SK_U32 Id,
+       char *pBuf, unsigned int *pLen, SK_U32 Instance,
+       unsigned int TableIndex, SK_U32 NetIndex);
+#endif /* SK_POWER_MGMT */
+
+#ifdef SK_DIAG_SUPPORT
+PNMI_STATIC int DiagActions(SK_AC *pAC, SK_IOC IoC, int action, SK_U32 Id,
+       char *pBuf, unsigned int *pLen, SK_U32 Instance,
+       unsigned int TableIndex, SK_U32 NetIndex);
+#endif /* SK_DIAG_SUPPORT */
+
+
+/* defines *******************************************************************/
+#define ID_TABLE_SIZE (sizeof(IdTable)/sizeof(IdTable[0]))
+
+
+/* global variables **********************************************************/
+
+/*
+ * Table to correlate OID with handler function and index to
+ * hardware register stored in StatAddress if applicable.
+ */
+PNMI_STATIC const SK_PNMI_TAB_ENTRY IdTable[] = {
+       {OID_GEN_XMIT_OK,
+               0,
+               0,
+               0,
+               SK_PNMI_RO, Mac8023Stat, SK_PNMI_HTX},
+       {OID_GEN_RCV_OK,
+               0,
+               0,
+               0,
+               SK_PNMI_RO, Mac8023Stat, SK_PNMI_HRX},
+       {OID_GEN_XMIT_ERROR,
+               0,
+               0,
+               0,
+               SK_PNMI_RO, General, 0},
+       {OID_GEN_RCV_ERROR,
+               0,
+               0,
+               0,
+               SK_PNMI_RO, General, 0},
+       {OID_GEN_RCV_NO_BUFFER,
+               0,
+               0,
+               0,
+               SK_PNMI_RO, General, 0},
+       {OID_GEN_DIRECTED_FRAMES_XMIT,
+               0,
+               0,
+               0,
+               SK_PNMI_RO, Mac8023Stat, SK_PNMI_HTX_UNICAST},
+       {OID_GEN_MULTICAST_FRAMES_XMIT,
+               0,
+               0,
+               0,
+               SK_PNMI_RO, Mac8023Stat, SK_PNMI_HTX_MULTICAST},
+       {OID_GEN_BROADCAST_FRAMES_XMIT,
+               0,
+               0,
+               0,
+               SK_PNMI_RO, Mac8023Stat, SK_PNMI_HTX_BROADCAST},
+       {OID_GEN_DIRECTED_FRAMES_RCV,
+               0,
+               0,
+               0,
+               SK_PNMI_RO, Mac8023Stat, SK_PNMI_HRX_UNICAST},
+       {OID_GEN_MULTICAST_FRAMES_RCV,
+               0,
+               0,
+               0,
+               SK_PNMI_RO, Mac8023Stat, SK_PNMI_HRX_MULTICAST},
+       {OID_GEN_BROADCAST_FRAMES_RCV,
+               0,
+               0,
+               0,
+               SK_PNMI_RO, Mac8023Stat, SK_PNMI_HRX_BROADCAST},
+       {OID_GEN_RCV_CRC_ERROR,
+               0,
+               0,
+               0,
+               SK_PNMI_RO, Mac8023Stat, SK_PNMI_HRX_FCS},
+       {OID_GEN_TRANSMIT_QUEUE_LENGTH,
+               0,
+               0,
+               0,
+               SK_PNMI_RO, General, 0},
+       {OID_802_3_PERMANENT_ADDRESS,
+               0,
+               0,
+               0,
+               SK_PNMI_RO, Mac8023Stat, 0},
+       {OID_802_3_CURRENT_ADDRESS,
+               0,
+               0,
+               0,
+               SK_PNMI_RO, Mac8023Stat, 0},
+       {OID_802_3_RCV_ERROR_ALIGNMENT,
+               0,
+               0,
+               0,
+               SK_PNMI_RO, Mac8023Stat, SK_PNMI_HRX_FRAMING},
+       {OID_802_3_XMIT_ONE_COLLISION,
+               0,
+               0,
+               0,
+               SK_PNMI_RO, Mac8023Stat, SK_PNMI_HTX_SINGLE_COL},
+       {OID_802_3_XMIT_MORE_COLLISIONS,
+               0,
+               0,
+               0,
+               SK_PNMI_RO, Mac8023Stat, SK_PNMI_HTX_MULTI_COL},
+       {OID_802_3_XMIT_DEFERRED,
+               0,
+               0,
+               0,
+               SK_PNMI_RO, Mac8023Stat, SK_PNMI_HTX_DEFFERAL},
+       {OID_802_3_XMIT_MAX_COLLISIONS,
+               0,
+               0,
+               0,
+               SK_PNMI_RO, Mac8023Stat, SK_PNMI_HTX_EXCESS_COL},
+       {OID_802_3_RCV_OVERRUN,
+               0,
+               0,
+               0,
+               SK_PNMI_RO, Mac8023Stat, SK_PNMI_HRX_OVERFLOW},
+       {OID_802_3_XMIT_UNDERRUN,
+               0,
+               0,
+               0,
+               SK_PNMI_RO, Mac8023Stat, SK_PNMI_HTX_UNDERRUN},
+       {OID_802_3_XMIT_TIMES_CRS_LOST,
+               0,
+               0,
+               0,
+               SK_PNMI_RO, Mac8023Stat, SK_PNMI_HTX_CARRIER},
+       {OID_802_3_XMIT_LATE_COLLISIONS,
+               0,
+               0,
+               0,
+               SK_PNMI_RO, Mac8023Stat, SK_PNMI_HTX_LATE_COL},
+#ifdef SK_POWER_MGMT
+       {OID_PNP_CAPABILITIES,
+               0,
+               0,
+               0,
+               SK_PNMI_RO, PowerManagement, 0},
+       {OID_PNP_SET_POWER,
+               0,
+               0,
+               0,
+               SK_PNMI_WO, PowerManagement, 0},
+       {OID_PNP_QUERY_POWER,
+               0,
+               0,
+               0,
+               SK_PNMI_RO, PowerManagement, 0},
+       {OID_PNP_ADD_WAKE_UP_PATTERN,
+               0,
+               0,
+               0,
+               SK_PNMI_WO, PowerManagement, 0},
+       {OID_PNP_REMOVE_WAKE_UP_PATTERN,
+               0,
+               0,
+               0,
+               SK_PNMI_WO, PowerManagement, 0},
+       {OID_PNP_ENABLE_WAKE_UP,
+               0,
+               0,
+               0,
+               SK_PNMI_RW, PowerManagement, 0},
+#endif /* SK_POWER_MGMT */
+#ifdef SK_DIAG_SUPPORT
+       {OID_SKGE_DIAG_MODE,
+               0,
+               0,
+               0,
+               SK_PNMI_RW, DiagActions, 0},
+#endif /* SK_DIAG_SUPPORT */
+       {OID_SKGE_MDB_VERSION,
+               1,
+               0,
+               SK_PNMI_MAI_OFF(MgmtDBVersion),
+               SK_PNMI_RO, General, 0},
+       {OID_SKGE_SUPPORTED_LIST,
+               0,
+               0,
+               0,
+               SK_PNMI_RO, General, 0},
+       {OID_SKGE_ALL_DATA,
+               0,
+               0,
+               0,
+               SK_PNMI_RW, OidStruct, 0},
+       {OID_SKGE_VPD_FREE_BYTES,
+               1,
+               0,
+               SK_PNMI_MAI_OFF(VpdFreeBytes),
+               SK_PNMI_RO, Vpd, 0},
+       {OID_SKGE_VPD_ENTRIES_LIST,
+               1,
+               0,
+               SK_PNMI_MAI_OFF(VpdEntriesList),
+               SK_PNMI_RO, Vpd, 0},
+       {OID_SKGE_VPD_ENTRIES_NUMBER,
+               1,
+               0,
+               SK_PNMI_MAI_OFF(VpdEntriesNumber),
+               SK_PNMI_RO, Vpd, 0},
+       {OID_SKGE_VPD_KEY,
+               SK_PNMI_VPD_ENTRIES,
+               sizeof(SK_PNMI_VPD),
+               SK_PNMI_OFF(Vpd) + SK_PNMI_VPD_OFF(VpdKey),
+               SK_PNMI_RO, Vpd, 0},
+       {OID_SKGE_VPD_VALUE,
+               SK_PNMI_VPD_ENTRIES,
+               sizeof(SK_PNMI_VPD),
+               SK_PNMI_OFF(Vpd) + SK_PNMI_VPD_OFF(VpdValue),
+               SK_PNMI_RO, Vpd, 0},
+       {OID_SKGE_VPD_ACCESS,
+               SK_PNMI_VPD_ENTRIES,
+               sizeof(SK_PNMI_VPD),
+               SK_PNMI_OFF(Vpd) + SK_PNMI_VPD_OFF(VpdAccess),
+               SK_PNMI_RO, Vpd, 0},
+       {OID_SKGE_VPD_ACTION,
+               SK_PNMI_VPD_ENTRIES,
+               sizeof(SK_PNMI_VPD),
+               SK_PNMI_OFF(Vpd) + SK_PNMI_VPD_OFF(VpdAction),
+               SK_PNMI_RW, Vpd, 0},
+       {OID_SKGE_PORT_NUMBER,          
+               1,
+               0,
+               SK_PNMI_MAI_OFF(PortNumber),
+               SK_PNMI_RO, General, 0},
+       {OID_SKGE_DEVICE_TYPE,
+               1,
+               0,
+               SK_PNMI_MAI_OFF(DeviceType),
+               SK_PNMI_RO, General, 0},
+       {OID_SKGE_DRIVER_DESCR,
+               1,
+               0,
+               SK_PNMI_MAI_OFF(DriverDescr),
+               SK_PNMI_RO, General, 0},
+       {OID_SKGE_DRIVER_VERSION,
+               1,
+               0,
+               SK_PNMI_MAI_OFF(DriverVersion),
+               SK_PNMI_RO, General, 0},
+       {OID_SKGE_DRIVER_RELDATE,
+               1,
+               0,
+               SK_PNMI_MAI_OFF(DriverReleaseDate),
+               SK_PNMI_RO, General, 0},
+       {OID_SKGE_DRIVER_FILENAME,
+               1,
+               0,
+               SK_PNMI_MAI_OFF(DriverFileName),
+               SK_PNMI_RO, General, 0},
+       {OID_SKGE_HW_DESCR,
+               1,
+               0,
+               SK_PNMI_MAI_OFF(HwDescr),
+               SK_PNMI_RO, General, 0},
+       {OID_SKGE_HW_VERSION,
+               1,
+               0,
+               SK_PNMI_MAI_OFF(HwVersion),
+               SK_PNMI_RO, General, 0},
+       {OID_SKGE_CHIPSET,
+               1,
+               0,
+               SK_PNMI_MAI_OFF(Chipset),
+               SK_PNMI_RO, General, 0},
+       {OID_SKGE_CHIPID,
+               1,
+               0,
+               SK_PNMI_MAI_OFF(ChipId),
+               SK_PNMI_RO, General, 0},
+       {OID_SKGE_RAMSIZE,
+               1,
+               0,
+               SK_PNMI_MAI_OFF(RamSize),
+               SK_PNMI_RO, General, 0},
+       {OID_SKGE_VAUXAVAIL,
+               1,
+               0,
+               SK_PNMI_MAI_OFF(VauxAvail),
+               SK_PNMI_RO, General, 0},
+       {OID_SKGE_ACTION,
+               1,
+               0,
+               SK_PNMI_MAI_OFF(Action),
+               SK_PNMI_RW, Perform, 0},
+       {OID_SKGE_RESULT,
+               1,
+               0,
+               SK_PNMI_MAI_OFF(TestResult),
+               SK_PNMI_RO, General, 0},
+       {OID_SKGE_BUS_TYPE,
+               1,
+               0,
+               SK_PNMI_MAI_OFF(BusType),
+               SK_PNMI_RO, General, 0},
+       {OID_SKGE_BUS_SPEED,
+               1,
+               0,
+               SK_PNMI_MAI_OFF(BusSpeed),
+               SK_PNMI_RO, General, 0},
+       {OID_SKGE_BUS_WIDTH,
+               1,
+               0,
+               SK_PNMI_MAI_OFF(BusWidth),
+               SK_PNMI_RO, General, 0},
+       {OID_SKGE_TX_SW_QUEUE_LEN,
+               1,
+               0,
+               SK_PNMI_MAI_OFF(TxSwQueueLen),
+               SK_PNMI_RO, General, 0},
+       {OID_SKGE_TX_SW_QUEUE_MAX,
+               1,
+               0,
+               SK_PNMI_MAI_OFF(TxSwQueueMax),
+               SK_PNMI_RO, General, 0},
+       {OID_SKGE_TX_RETRY,
+               1,
+               0,
+               SK_PNMI_MAI_OFF(TxRetryCts),
+               SK_PNMI_RO, General, 0},
+       {OID_SKGE_RX_INTR_CTS,
+               1,
+               0,
+               SK_PNMI_MAI_OFF(RxIntrCts),
+               SK_PNMI_RO, General, 0},
+       {OID_SKGE_TX_INTR_CTS,
+               1,
+               0,
+               SK_PNMI_MAI_OFF(TxIntrCts),
+               SK_PNMI_RO, General, 0},
+       {OID_SKGE_RX_NO_BUF_CTS,
+               1,
+               0,
+               SK_PNMI_MAI_OFF(RxNoBufCts),
+               SK_PNMI_RO, General, 0},
+       {OID_SKGE_TX_NO_BUF_CTS,
+               1,
+               0,
+               SK_PNMI_MAI_OFF(TxNoBufCts),
+               SK_PNMI_RO, General, 0},
+       {OID_SKGE_TX_USED_DESCR_NO,
+               1,
+               0,
+               SK_PNMI_MAI_OFF(TxUsedDescrNo),
+               SK_PNMI_RO, General, 0},
+       {OID_SKGE_RX_DELIVERED_CTS,
+               1,
+               0,
+               SK_PNMI_MAI_OFF(RxDeliveredCts),
+               SK_PNMI_RO, General, 0},
+       {OID_SKGE_RX_OCTETS_DELIV_CTS,
+               1,
+               0,
+               SK_PNMI_MAI_OFF(RxOctetsDeliveredCts),
+               SK_PNMI_RO, General, 0},
+       {OID_SKGE_RX_HW_ERROR_CTS,
+               1,
+               0,
+               SK_PNMI_MAI_OFF(RxHwErrorsCts),
+               SK_PNMI_RO, General, 0},
+       {OID_SKGE_TX_HW_ERROR_CTS,
+               1,
+               0,
+               SK_PNMI_MAI_OFF(TxHwErrorsCts),
+               SK_PNMI_RO, General, 0},
+       {OID_SKGE_IN_ERRORS_CTS,
+               1,
+               0,
+               SK_PNMI_MAI_OFF(InErrorsCts),
+               SK_PNMI_RO, General, 0},
+       {OID_SKGE_OUT_ERROR_CTS,
+               1,
+               0,
+               SK_PNMI_MAI_OFF(OutErrorsCts),
+               SK_PNMI_RO, General, 0},
+       {OID_SKGE_ERR_RECOVERY_CTS,
+               1,
+               0,
+               SK_PNMI_MAI_OFF(ErrRecoveryCts),
+               SK_PNMI_RO, General, 0},
+       {OID_SKGE_SYSUPTIME,
+               1,
+               0,
+               SK_PNMI_MAI_OFF(SysUpTime),
+               SK_PNMI_RO, General, 0},
+       {OID_SKGE_SENSOR_NUMBER,
+               1,
+               0,
+               SK_PNMI_MAI_OFF(SensorNumber),
+               SK_PNMI_RO, General, 0},
+       {OID_SKGE_SENSOR_INDEX,
+               SK_PNMI_SENSOR_ENTRIES,
+               sizeof(SK_PNMI_SENSOR),
+               SK_PNMI_OFF(Sensor) + SK_PNMI_SEN_OFF(SensorIndex),
+               SK_PNMI_RO, SensorStat, 0},
+       {OID_SKGE_SENSOR_DESCR,
+               SK_PNMI_SENSOR_ENTRIES,
+               sizeof(SK_PNMI_SENSOR),
+               SK_PNMI_OFF(Sensor) + SK_PNMI_SEN_OFF(SensorDescr),
+               SK_PNMI_RO, SensorStat, 0},
+       {OID_SKGE_SENSOR_TYPE,
+               SK_PNMI_SENSOR_ENTRIES,
+               sizeof(SK_PNMI_SENSOR),
+               SK_PNMI_OFF(Sensor) + SK_PNMI_SEN_OFF(SensorType),
+               SK_PNMI_RO, SensorStat, 0},
+       {OID_SKGE_SENSOR_VALUE,
+               SK_PNMI_SENSOR_ENTRIES,
+               sizeof(SK_PNMI_SENSOR),
+               SK_PNMI_OFF(Sensor) + SK_PNMI_SEN_OFF(SensorValue),
+               SK_PNMI_RO, SensorStat, 0},
+       {OID_SKGE_SENSOR_WAR_THRES_LOW,
+               SK_PNMI_SENSOR_ENTRIES,
+               sizeof(SK_PNMI_SENSOR),
+               SK_PNMI_OFF(Sensor) + SK_PNMI_SEN_OFF(SensorWarningThresholdLow),
+               SK_PNMI_RO, SensorStat, 0},
+       {OID_SKGE_SENSOR_WAR_THRES_UPP,
+               SK_PNMI_SENSOR_ENTRIES,
+               sizeof(SK_PNMI_SENSOR),
+               SK_PNMI_OFF(Sensor) + SK_PNMI_SEN_OFF(SensorWarningThresholdHigh),
+               SK_PNMI_RO, SensorStat, 0},
+       {OID_SKGE_SENSOR_ERR_THRES_LOW,
+               SK_PNMI_SENSOR_ENTRIES,
+               sizeof(SK_PNMI_SENSOR),
+               SK_PNMI_OFF(Sensor) + SK_PNMI_SEN_OFF(SensorErrorThresholdLow),
+               SK_PNMI_RO, SensorStat, 0},
+       {OID_SKGE_SENSOR_ERR_THRES_UPP,
+               SK_PNMI_SENSOR_ENTRIES,
+               sizeof(SK_PNMI_SENSOR),
+               SK_PNMI_OFF(Sensor) + SK_PNMI_SEN_OFF(SensorErrorThresholdHigh),
+               SK_PNMI_RO, SensorStat, 0},
+       {OID_SKGE_SENSOR_STATUS,
+               SK_PNMI_SENSOR_ENTRIES,
+               sizeof(SK_PNMI_SENSOR),
+               SK_PNMI_OFF(Sensor) + SK_PNMI_SEN_OFF(SensorStatus),
+               SK_PNMI_RO, SensorStat, 0},
+       {OID_SKGE_SENSOR_WAR_CTS,
+               SK_PNMI_SENSOR_ENTRIES,
+               sizeof(SK_PNMI_SENSOR),
+               SK_PNMI_OFF(Sensor) + SK_PNMI_SEN_OFF(SensorWarningCts),
+               SK_PNMI_RO, SensorStat, 0},
+       {OID_SKGE_SENSOR_ERR_CTS,
+               SK_PNMI_SENSOR_ENTRIES,
+               sizeof(SK_PNMI_SENSOR),
+               SK_PNMI_OFF(Sensor) + SK_PNMI_SEN_OFF(SensorErrorCts),
+               SK_PNMI_RO, SensorStat, 0},
+       {OID_SKGE_SENSOR_WAR_TIME,
+               SK_PNMI_SENSOR_ENTRIES,
+               sizeof(SK_PNMI_SENSOR),
+               SK_PNMI_OFF(Sensor) + SK_PNMI_SEN_OFF(SensorWarningTimestamp),
+               SK_PNMI_RO, SensorStat, 0},
+       {OID_SKGE_SENSOR_ERR_TIME,
+               SK_PNMI_SENSOR_ENTRIES,
+               sizeof(SK_PNMI_SENSOR),
+               SK_PNMI_OFF(Sensor) + SK_PNMI_SEN_OFF(SensorErrorTimestamp),
+               SK_PNMI_RO, SensorStat, 0},
+       {OID_SKGE_CHKSM_NUMBER,
+               1,
+               0,
+               SK_PNMI_MAI_OFF(ChecksumNumber),
+               SK_PNMI_RO, General, 0},
+       {OID_SKGE_CHKSM_RX_OK_CTS,
+               SKCS_NUM_PROTOCOLS,
+               sizeof(SK_PNMI_CHECKSUM),
+               SK_PNMI_OFF(Checksum) + SK_PNMI_CHK_OFF(ChecksumRxOkCts),
+               SK_PNMI_RO, CsumStat, 0},
+       {OID_SKGE_CHKSM_RX_UNABLE_CTS,
+               SKCS_NUM_PROTOCOLS,
+               sizeof(SK_PNMI_CHECKSUM),
+               SK_PNMI_OFF(Checksum) + SK_PNMI_CHK_OFF(ChecksumRxUnableCts),
+               SK_PNMI_RO, CsumStat, 0},
+       {OID_SKGE_CHKSM_RX_ERR_CTS,
+               SKCS_NUM_PROTOCOLS,
+               sizeof(SK_PNMI_CHECKSUM),
+               SK_PNMI_OFF(Checksum) + SK_PNMI_CHK_OFF(ChecksumRxErrCts),
+               SK_PNMI_RO, CsumStat, 0},
+       {OID_SKGE_CHKSM_TX_OK_CTS,
+               SKCS_NUM_PROTOCOLS,
+               sizeof(SK_PNMI_CHECKSUM),
+               SK_PNMI_OFF(Checksum) + SK_PNMI_CHK_OFF(ChecksumTxOkCts),
+               SK_PNMI_RO, CsumStat, 0},
+       {OID_SKGE_CHKSM_TX_UNABLE_CTS,
+               SKCS_NUM_PROTOCOLS,
+               sizeof(SK_PNMI_CHECKSUM),
+               SK_PNMI_OFF(Checksum) + SK_PNMI_CHK_OFF(ChecksumTxUnableCts),
+               SK_PNMI_RO, CsumStat, 0},
+       {OID_SKGE_STAT_TX,
+               SK_PNMI_MAC_ENTRIES,
+               sizeof(SK_PNMI_STAT),
+               SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTxOkCts),
+               SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX},
+       {OID_SKGE_STAT_TX_OCTETS,
+               SK_PNMI_MAC_ENTRIES,
+               sizeof(SK_PNMI_STAT),
+               SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTxOctetsOkCts),
+               SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_OCTET},
+       {OID_SKGE_STAT_TX_BROADCAST,
+               SK_PNMI_MAC_ENTRIES,
+               sizeof(SK_PNMI_STAT),
+               SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTxBroadcastOkCts),
+               SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_BROADCAST},
+       {OID_SKGE_STAT_TX_MULTICAST,
+               SK_PNMI_MAC_ENTRIES,
+               sizeof(SK_PNMI_STAT),
+               SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTxMulticastOkCts),
+               SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_MULTICAST},
+       {OID_SKGE_STAT_TX_UNICAST,
+               SK_PNMI_MAC_ENTRIES,
+               sizeof(SK_PNMI_STAT),
+               SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTxUnicastOkCts),
+               SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_UNICAST},
+       {OID_SKGE_STAT_TX_LONGFRAMES,
+               SK_PNMI_MAC_ENTRIES,
+               sizeof(SK_PNMI_STAT),
+               SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTxLongFramesCts),
+               SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_LONGFRAMES},
+       {OID_SKGE_STAT_TX_BURST,
+               SK_PNMI_MAC_ENTRIES,
+               sizeof(SK_PNMI_STAT),
+               SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTxBurstCts),
+               SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_BURST},
+       {OID_SKGE_STAT_TX_PFLOWC,
+               SK_PNMI_MAC_ENTRIES,
+               sizeof(SK_PNMI_STAT),
+               SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTxPauseMacCtrlCts),
+               SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_PMACC},
+       {OID_SKGE_STAT_TX_FLOWC,
+               SK_PNMI_MAC_ENTRIES,
+               sizeof(SK_PNMI_STAT),
+               SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTxMacCtrlCts),
+               SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_MACC},
+       {OID_SKGE_STAT_TX_SINGLE_COL,
+               SK_PNMI_MAC_ENTRIES,
+               sizeof(SK_PNMI_STAT),
+               SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTxSingleCollisionCts),
+               SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_SINGLE_COL},
+       {OID_SKGE_STAT_TX_MULTI_COL,
+               SK_PNMI_MAC_ENTRIES,
+               sizeof(SK_PNMI_STAT),
+               SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTxMultipleCollisionCts),
+               SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_MULTI_COL},
+       {OID_SKGE_STAT_TX_EXCESS_COL,
+               SK_PNMI_MAC_ENTRIES,
+               sizeof(SK_PNMI_STAT),
+               SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTxExcessiveCollisionCts),
+               SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_EXCESS_COL},
+       {OID_SKGE_STAT_TX_LATE_COL,
+               SK_PNMI_MAC_ENTRIES,
+               sizeof(SK_PNMI_STAT),
+               SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTxLateCollisionCts),
+               SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_LATE_COL},
+       {OID_SKGE_STAT_TX_DEFFERAL,
+               SK_PNMI_MAC_ENTRIES,
+               sizeof(SK_PNMI_STAT),
+               SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTxDeferralCts),
+               SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_DEFFERAL},
+       {OID_SKGE_STAT_TX_EXCESS_DEF,
+               SK_PNMI_MAC_ENTRIES,
+               sizeof(SK_PNMI_STAT),
+               SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTxExcessiveDeferralCts),
+               SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_EXCESS_DEF},
+       {OID_SKGE_STAT_TX_UNDERRUN,
+               SK_PNMI_MAC_ENTRIES,
+               sizeof(SK_PNMI_STAT),
+               SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTxFifoUnderrunCts),
+               SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_UNDERRUN},
+       {OID_SKGE_STAT_TX_CARRIER,
+               SK_PNMI_MAC_ENTRIES,
+               sizeof(SK_PNMI_STAT),
+               SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTxCarrierCts),
+               SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_CARRIER},
+/*     {OID_SKGE_STAT_TX_UTIL,
+               SK_PNMI_MAC_ENTRIES,
+               sizeof(SK_PNMI_STAT),
+               SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTxUtilization),
+               SK_PNMI_RO, MacPrivateStat, (SK_U16)(-1)}, */
+       {OID_SKGE_STAT_TX_64,
+               SK_PNMI_MAC_ENTRIES,
+               sizeof(SK_PNMI_STAT),
+               SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTx64Cts),
+               SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_64},
+       {OID_SKGE_STAT_TX_127,
+               SK_PNMI_MAC_ENTRIES,
+               sizeof(SK_PNMI_STAT),
+               SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTx127Cts),
+               SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_127},
+       {OID_SKGE_STAT_TX_255,
+               SK_PNMI_MAC_ENTRIES,
+               sizeof(SK_PNMI_STAT),
+               SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTx255Cts),
+               SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_255},
+       {OID_SKGE_STAT_TX_511,
+               SK_PNMI_MAC_ENTRIES,
+               sizeof(SK_PNMI_STAT),
+               SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTx511Cts),
+               SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_511},
+       {OID_SKGE_STAT_TX_1023,
+               SK_PNMI_MAC_ENTRIES,
+               sizeof(SK_PNMI_STAT),
+               SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTx1023Cts),
+               SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_1023},
+       {OID_SKGE_STAT_TX_MAX,
+               SK_PNMI_MAC_ENTRIES,
+               sizeof(SK_PNMI_STAT),
+               SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTxMaxCts),
+               SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_MAX},
+       {OID_SKGE_STAT_TX_SYNC,
+               SK_PNMI_MAC_ENTRIES,
+               sizeof(SK_PNMI_STAT),
+               SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTxSyncCts),
+               SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_SYNC},
+       {OID_SKGE_STAT_TX_SYNC_OCTETS,
+               SK_PNMI_MAC_ENTRIES,
+               sizeof(SK_PNMI_STAT),
+               SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTxSyncOctetsCts),
+               SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_SYNC_OCTET},
+       {OID_SKGE_STAT_RX,
+               SK_PNMI_MAC_ENTRIES,
+               sizeof(SK_PNMI_STAT),
+               SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxOkCts),
+               SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX},
+       {OID_SKGE_STAT_RX_OCTETS,
+               SK_PNMI_MAC_ENTRIES,
+               sizeof(SK_PNMI_STAT),
+               SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxOctetsOkCts),
+               SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_OCTET},
+       {OID_SKGE_STAT_RX_BROADCAST,
+               SK_PNMI_MAC_ENTRIES,
+               sizeof(SK_PNMI_STAT),
+               SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxBroadcastOkCts),
+               SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_BROADCAST},
+       {OID_SKGE_STAT_RX_MULTICAST,
+               SK_PNMI_MAC_ENTRIES,
+               sizeof(SK_PNMI_STAT),
+               SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxMulticastOkCts),
+               SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_MULTICAST},
+       {OID_SKGE_STAT_RX_UNICAST,
+               SK_PNMI_MAC_ENTRIES,
+               sizeof(SK_PNMI_STAT),
+               SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxUnicastOkCts),
+               SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_UNICAST},
+       {OID_SKGE_STAT_RX_LONGFRAMES,
+               SK_PNMI_MAC_ENTRIES,
+               sizeof(SK_PNMI_STAT),
+               SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxLongFramesCts),
+               SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_LONGFRAMES},
+       {OID_SKGE_STAT_RX_PFLOWC,
+               SK_PNMI_MAC_ENTRIES,
+               sizeof(SK_PNMI_STAT),
+               SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxPauseMacCtrlCts),
+               SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_PMACC},
+       {OID_SKGE_STAT_RX_FLOWC,
+               SK_PNMI_MAC_ENTRIES,
+               sizeof(SK_PNMI_STAT),
+               SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxMacCtrlCts),
+               SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_MACC},
+       {OID_SKGE_STAT_RX_PFLOWC_ERR,
+               SK_PNMI_MAC_ENTRIES,
+               sizeof(SK_PNMI_STAT),
+               SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxPauseMacCtrlErrorCts),
+               SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_PMACC_ERR},
+       {OID_SKGE_STAT_RX_FLOWC_UNKWN,
+               SK_PNMI_MAC_ENTRIES,
+               sizeof(SK_PNMI_STAT),
+               SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxMacCtrlUnknownCts),
+               SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_MACC_UNKWN},
+       {OID_SKGE_STAT_RX_BURST,
+               SK_PNMI_MAC_ENTRIES,
+               sizeof(SK_PNMI_STAT),
+               SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxBurstCts),
+               SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_BURST},
+       {OID_SKGE_STAT_RX_MISSED,
+               SK_PNMI_MAC_ENTRIES,
+               sizeof(SK_PNMI_STAT),
+               SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxMissedCts),
+               SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_MISSED},
+       {OID_SKGE_STAT_RX_FRAMING,
+               SK_PNMI_MAC_ENTRIES,
+               sizeof(SK_PNMI_STAT),
+               SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxFramingCts),
+               SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_FRAMING},
+       {OID_SKGE_STAT_RX_OVERFLOW,
+               SK_PNMI_MAC_ENTRIES,
+               sizeof(SK_PNMI_STAT),
+               SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxFifoOverflowCts),
+               SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_OVERFLOW},
+       {OID_SKGE_STAT_RX_JABBER,
+               SK_PNMI_MAC_ENTRIES,
+               sizeof(SK_PNMI_STAT),
+               SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxJabberCts),
+               SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_JABBER},
+       {OID_SKGE_STAT_RX_CARRIER,
+               SK_PNMI_MAC_ENTRIES,
+               sizeof(SK_PNMI_STAT),
+               SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxCarrierCts),
+               SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_CARRIER},
+       {OID_SKGE_STAT_RX_IR_LENGTH,
+               SK_PNMI_MAC_ENTRIES,
+               sizeof(SK_PNMI_STAT),
+               SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxIRLengthCts),
+               SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_IRLENGTH},
+       {OID_SKGE_STAT_RX_SYMBOL,
+               SK_PNMI_MAC_ENTRIES,
+               sizeof(SK_PNMI_STAT),
+               SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxSymbolCts),
+               SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_SYMBOL},
+       {OID_SKGE_STAT_RX_SHORTS,
+               SK_PNMI_MAC_ENTRIES,
+               sizeof(SK_PNMI_STAT),
+               SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxShortsCts),
+               SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_SHORTS},
+       {OID_SKGE_STAT_RX_RUNT,
+               SK_PNMI_MAC_ENTRIES,
+               sizeof(SK_PNMI_STAT),
+               SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxRuntCts),
+               SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_RUNT},
+       {OID_SKGE_STAT_RX_CEXT,
+               SK_PNMI_MAC_ENTRIES,
+               sizeof(SK_PNMI_STAT),
+               SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxCextCts),
+               SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_CEXT},
+       {OID_SKGE_STAT_RX_TOO_LONG,
+               SK_PNMI_MAC_ENTRIES,
+               sizeof(SK_PNMI_STAT),
+               SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxTooLongCts),
+               SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_TOO_LONG},
+       {OID_SKGE_STAT_RX_FCS,
+               SK_PNMI_MAC_ENTRIES,
+               sizeof(SK_PNMI_STAT),
+               SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxFcsCts),
+               SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_FCS},
+/*     {OID_SKGE_STAT_RX_UTIL,
+               SK_PNMI_MAC_ENTRIES,
+               sizeof(SK_PNMI_STAT),
+               SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxUtilization),
+               SK_PNMI_RO, MacPrivateStat, (SK_U16)(-1)}, */
+       {OID_SKGE_STAT_RX_64,
+               SK_PNMI_MAC_ENTRIES,
+               sizeof(SK_PNMI_STAT),
+               SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRx64Cts),
+               SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_64},
+       {OID_SKGE_STAT_RX_127,
+               SK_PNMI_MAC_ENTRIES,
+               sizeof(SK_PNMI_STAT),
+               SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRx127Cts),
+               SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_127},
+       {OID_SKGE_STAT_RX_255,
+               SK_PNMI_MAC_ENTRIES,
+               sizeof(SK_PNMI_STAT),
+               SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRx255Cts),
+               SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_255},
+       {OID_SKGE_STAT_RX_511,
+               SK_PNMI_MAC_ENTRIES,
+               sizeof(SK_PNMI_STAT),
+               SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRx511Cts),
+               SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_511},
+       {OID_SKGE_STAT_RX_1023,
+               SK_PNMI_MAC_ENTRIES,
+               sizeof(SK_PNMI_STAT),
+               SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRx1023Cts),
+               SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_1023},
+       {OID_SKGE_STAT_RX_MAX,
+               SK_PNMI_MAC_ENTRIES,
+               sizeof(SK_PNMI_STAT),
+               SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxMaxCts),
+               SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_MAX},
+       {OID_SKGE_PHYS_CUR_ADDR,
+               SK_PNMI_MAC_ENTRIES,
+               sizeof(SK_PNMI_CONF),
+               SK_PNMI_OFF(Conf) + SK_PNMI_CNF_OFF(ConfMacCurrentAddr),
+               SK_PNMI_RW, Addr, 0},
+       {OID_SKGE_PHYS_FAC_ADDR,
+               SK_PNMI_MAC_ENTRIES,
+               sizeof(SK_PNMI_CONF),
+               SK_PNMI_OFF(Conf) + SK_PNMI_CNF_OFF(ConfMacFactoryAddr),
+               SK_PNMI_RO, Addr, 0},
+       {OID_SKGE_PMD,
+               SK_PNMI_MAC_ENTRIES,
+               sizeof(SK_PNMI_CONF),
+               SK_PNMI_OFF(Conf) + SK_PNMI_CNF_OFF(ConfPMD),
+               SK_PNMI_RO, MacPrivateConf, 0},
+       {OID_SKGE_CONNECTOR,
+               SK_PNMI_MAC_ENTRIES,
+               sizeof(SK_PNMI_CONF),
+               SK_PNMI_OFF(Conf) + SK_PNMI_CNF_OFF(ConfConnector),
+               SK_PNMI_RO, MacPrivateConf, 0},
+       {OID_SKGE_PHY_TYPE,
+               SK_PNMI_MAC_ENTRIES,
+               sizeof(SK_PNMI_CONF),
+               SK_PNMI_OFF(Conf) + SK_PNMI_CNF_OFF(ConfPhyType),
+               SK_PNMI_RO, MacPrivateConf, 0},
+       {OID_SKGE_LINK_CAP,
+               SK_PNMI_MAC_ENTRIES,
+               sizeof(SK_PNMI_CONF),
+               SK_PNMI_OFF(Conf) + SK_PNMI_CNF_OFF(ConfLinkCapability),
+               SK_PNMI_RO, MacPrivateConf, 0},
+       {OID_SKGE_LINK_MODE,
+               SK_PNMI_MAC_ENTRIES,
+               sizeof(SK_PNMI_CONF),
+               SK_PNMI_OFF(Conf) + SK_PNMI_CNF_OFF(ConfLinkMode),
+               SK_PNMI_RW, MacPrivateConf, 0},
+       {OID_SKGE_LINK_MODE_STATUS,
+               SK_PNMI_MAC_ENTRIES,
+               sizeof(SK_PNMI_CONF),
+               SK_PNMI_OFF(Conf) + SK_PNMI_CNF_OFF(ConfLinkModeStatus),
+               SK_PNMI_RO, MacPrivateConf, 0},
+       {OID_SKGE_LINK_STATUS,
+               SK_PNMI_MAC_ENTRIES,
+               sizeof(SK_PNMI_CONF),
+               SK_PNMI_OFF(Conf) + SK_PNMI_CNF_OFF(ConfLinkStatus),
+               SK_PNMI_RO, MacPrivateConf, 0},
+       {OID_SKGE_FLOWCTRL_CAP,
+               SK_PNMI_MAC_ENTRIES,
+               sizeof(SK_PNMI_CONF),
+               SK_PNMI_OFF(Conf) + SK_PNMI_CNF_OFF(ConfFlowCtrlCapability),
+               SK_PNMI_RO, MacPrivateConf, 0},
+       {OID_SKGE_FLOWCTRL_MODE,
+               SK_PNMI_MAC_ENTRIES,
+               sizeof(SK_PNMI_CONF),
+               SK_PNMI_OFF(Conf) + SK_PNMI_CNF_OFF(ConfFlowCtrlMode),
+               SK_PNMI_RW, MacPrivateConf, 0},
+       {OID_SKGE_FLOWCTRL_STATUS,
+               SK_PNMI_MAC_ENTRIES,
+               sizeof(SK_PNMI_CONF),
+               SK_PNMI_OFF(Conf) + SK_PNMI_CNF_OFF(ConfFlowCtrlStatus),
+               SK_PNMI_RO, MacPrivateConf, 0},
+       {OID_SKGE_PHY_OPERATION_CAP,
+               SK_PNMI_MAC_ENTRIES,
+               sizeof(SK_PNMI_CONF),
+               SK_PNMI_OFF(Conf) + SK_PNMI_CNF_OFF(ConfPhyOperationCapability),
+               SK_PNMI_RO, MacPrivateConf, 0},
+       {OID_SKGE_PHY_OPERATION_MODE,
+               SK_PNMI_MAC_ENTRIES,
+               sizeof(SK_PNMI_CONF),
+               SK_PNMI_OFF(Conf) + SK_PNMI_CNF_OFF(ConfPhyOperationMode),
+               SK_PNMI_RW, MacPrivateConf, 0},
+       {OID_SKGE_PHY_OPERATION_STATUS,
+               SK_PNMI_MAC_ENTRIES,
+               sizeof(SK_PNMI_CONF),
+               SK_PNMI_OFF(Conf) + SK_PNMI_CNF_OFF(ConfPhyOperationStatus),
+               SK_PNMI_RO, MacPrivateConf, 0},
+       {OID_SKGE_SPEED_CAP,
+               SK_PNMI_MAC_ENTRIES,
+               sizeof(SK_PNMI_CONF),
+               SK_PNMI_OFF(Conf) + SK_PNMI_CNF_OFF(ConfSpeedCapability),
+               SK_PNMI_RO, MacPrivateConf, 0},
+       {OID_SKGE_SPEED_MODE,
+               SK_PNMI_MAC_ENTRIES,
+               sizeof(SK_PNMI_CONF),
+               SK_PNMI_OFF(Conf) + SK_PNMI_CNF_OFF(ConfSpeedMode),
+               SK_PNMI_RW, MacPrivateConf, 0},
+       {OID_SKGE_SPEED_STATUS,
+               SK_PNMI_MAC_ENTRIES,
+               sizeof(SK_PNMI_CONF),
+               SK_PNMI_OFF(Conf) + SK_PNMI_CNF_OFF(ConfSpeedStatus),
+               SK_PNMI_RO, MacPrivateConf, 0},
+       {OID_SKGE_TRAP,
+               1,
+               0,
+               SK_PNMI_MAI_OFF(Trap),
+               SK_PNMI_RO, General, 0},
+       {OID_SKGE_TRAP_NUMBER,
+               1,
+               0,
+               SK_PNMI_MAI_OFF(TrapNumber),
+               SK_PNMI_RO, General, 0},
+       {OID_SKGE_RLMT_MODE,
+               1,
+               0,
+               SK_PNMI_MAI_OFF(RlmtMode),
+               SK_PNMI_RW, Rlmt, 0},
+       {OID_SKGE_RLMT_PORT_NUMBER,
+               1,
+               0,
+               SK_PNMI_MAI_OFF(RlmtPortNumber),
+               SK_PNMI_RO, Rlmt, 0},
+       {OID_SKGE_RLMT_PORT_ACTIVE,
+               1,
+               0,
+               SK_PNMI_MAI_OFF(RlmtPortActive),
+               SK_PNMI_RO, Rlmt, 0},
+       {OID_SKGE_RLMT_PORT_PREFERRED,
+               1,
+               0,
+               SK_PNMI_MAI_OFF(RlmtPortPreferred),
+               SK_PNMI_RW, Rlmt, 0},
+       {OID_SKGE_RLMT_CHANGE_CTS,
+               1,
+               0,
+               SK_PNMI_MAI_OFF(RlmtChangeCts),
+               SK_PNMI_RO, Rlmt, 0},
+       {OID_SKGE_RLMT_CHANGE_TIME,
+               1,
+               0,
+               SK_PNMI_MAI_OFF(RlmtChangeTime),
+               SK_PNMI_RO, Rlmt, 0},
+       {OID_SKGE_RLMT_CHANGE_ESTIM,
+               1,
+               0,
+               SK_PNMI_MAI_OFF(RlmtChangeEstimate),
+               SK_PNMI_RO, Rlmt, 0},
+       {OID_SKGE_RLMT_CHANGE_THRES,
+               1,
+               0,
+               SK_PNMI_MAI_OFF(RlmtChangeThreshold),
+               SK_PNMI_RW, Rlmt, 0},
+       {OID_SKGE_RLMT_PORT_INDEX,
+               SK_PNMI_MAC_ENTRIES,
+               sizeof(SK_PNMI_RLMT),
+               SK_PNMI_OFF(Rlmt) + SK_PNMI_RLM_OFF(RlmtIndex),
+               SK_PNMI_RO, RlmtStat, 0},
+       {OID_SKGE_RLMT_STATUS,
+               SK_PNMI_MAC_ENTRIES,
+               sizeof(SK_PNMI_RLMT),
+               SK_PNMI_OFF(Rlmt) + SK_PNMI_RLM_OFF(RlmtStatus),
+               SK_PNMI_RO, RlmtStat, 0},
+       {OID_SKGE_RLMT_TX_HELLO_CTS,
+               SK_PNMI_MAC_ENTRIES,
+               sizeof(SK_PNMI_RLMT),
+               SK_PNMI_OFF(Rlmt) + SK_PNMI_RLM_OFF(RlmtTxHelloCts),
+               SK_PNMI_RO, RlmtStat, 0},
+       {OID_SKGE_RLMT_RX_HELLO_CTS,
+               SK_PNMI_MAC_ENTRIES,
+               sizeof(SK_PNMI_RLMT),
+               SK_PNMI_OFF(Rlmt) + SK_PNMI_RLM_OFF(RlmtRxHelloCts),
+               SK_PNMI_RO, RlmtStat, 0},
+       {OID_SKGE_RLMT_TX_SP_REQ_CTS,
+               SK_PNMI_MAC_ENTRIES,
+               sizeof(SK_PNMI_RLMT),
+               SK_PNMI_OFF(Rlmt) + SK_PNMI_RLM_OFF(RlmtTxSpHelloReqCts),
+               SK_PNMI_RO, RlmtStat, 0},
+       {OID_SKGE_RLMT_RX_SP_CTS,
+               SK_PNMI_MAC_ENTRIES,
+               sizeof(SK_PNMI_RLMT),
+               SK_PNMI_OFF(Rlmt) + SK_PNMI_RLM_OFF(RlmtRxSpHelloCts),
+               SK_PNMI_RO, RlmtStat, 0},
+       {OID_SKGE_RLMT_MONITOR_NUMBER,
+               1,
+               0,
+               SK_PNMI_MAI_OFF(RlmtMonitorNumber),
+               SK_PNMI_RO, General, 0},
+       {OID_SKGE_RLMT_MONITOR_INDEX,
+               SK_PNMI_MONITOR_ENTRIES,
+               sizeof(SK_PNMI_RLMT_MONITOR),
+               SK_PNMI_OFF(RlmtMonitor) + SK_PNMI_MON_OFF(RlmtMonitorIndex),
+               SK_PNMI_RO, Monitor, 0},
+       {OID_SKGE_RLMT_MONITOR_ADDR,
+               SK_PNMI_MONITOR_ENTRIES,
+               sizeof(SK_PNMI_RLMT_MONITOR),
+               SK_PNMI_OFF(RlmtMonitor) + SK_PNMI_MON_OFF(RlmtMonitorAddr),
+               SK_PNMI_RO, Monitor, 0},
+       {OID_SKGE_RLMT_MONITOR_ERRS,
+               SK_PNMI_MONITOR_ENTRIES,
+               sizeof(SK_PNMI_RLMT_MONITOR),
+               SK_PNMI_OFF(RlmtMonitor) + SK_PNMI_MON_OFF(RlmtMonitorErrorCts),
+               SK_PNMI_RO, Monitor, 0},
+       {OID_SKGE_RLMT_MONITOR_TIMESTAMP,
+               SK_PNMI_MONITOR_ENTRIES,
+               sizeof(SK_PNMI_RLMT_MONITOR),
+               SK_PNMI_OFF(RlmtMonitor) + SK_PNMI_MON_OFF(RlmtMonitorTimestamp),
+               SK_PNMI_RO, Monitor, 0},
+       {OID_SKGE_RLMT_MONITOR_ADMIN,
+               SK_PNMI_MONITOR_ENTRIES,
+               sizeof(SK_PNMI_RLMT_MONITOR),
+               SK_PNMI_OFF(RlmtMonitor) + SK_PNMI_MON_OFF(RlmtMonitorAdmin),
+               SK_PNMI_RW, Monitor, 0},
+       {OID_SKGE_MTU,
+               1,
+               0,
+               SK_PNMI_MAI_OFF(MtuSize),
+               SK_PNMI_RW, MacPrivateConf, 0},
+       {OID_SKGE_VCT_GET,
+               0,
+               0,
+               0,
+               SK_PNMI_RO, Vct, 0},
+       {OID_SKGE_VCT_SET,
+               0,
+               0,
+               0,
+               SK_PNMI_WO, Vct, 0},
+       {OID_SKGE_VCT_STATUS,
+               0,
+               0,
+               0,
+               SK_PNMI_RO, Vct, 0},
+       {OID_SKGE_BOARDLEVEL,
+               0,
+               0,
+               0,
+               SK_PNMI_RO, General, 0},
+};
+
diff --git a/drivers/net/sk98lin/skgepnmi.c b/drivers/net/sk98lin/skgepnmi.c
new file mode 100644 (file)
index 0000000..b36dd9a
--- /dev/null
@@ -0,0 +1,8210 @@
+/*****************************************************************************
+ *
+ * Name:       skgepnmi.c
+ * Project:    GEnesis, PCI Gigabit Ethernet Adapter
+ * Version:    $Revision: 1.111 $
+ * Date:       $Date: 2003/09/15 13:35:35 $
+ * Purpose:    Private Network Management Interface
+ *
+ ****************************************************************************/
+
+/******************************************************************************
+ *
+ *     (C)Copyright 1998-2002 SysKonnect GmbH.
+ *     (C)Copyright 2002-2003 Marvell.
+ *
+ *     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.
+ *
+ *     The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+
+#ifndef _lint
+static const char SysKonnectFileId[] =
+       "@(#) $Id: skgepnmi.c,v 1.111 2003/09/15 13:35:35 tschilli Exp $ (C) Marvell.";
+#endif /* !_lint */
+
+#include "h/skdrv1st.h"
+#include "h/sktypes.h"
+#include "h/xmac_ii.h"
+#include "h/skdebug.h"
+#include "h/skqueue.h"
+#include "h/skgepnmi.h"
+#include "h/skgesirq.h"
+#include "h/skcsum.h"
+#include "h/skvpd.h"
+#include "h/skgehw.h"
+#include "h/skgeinit.h"
+#include "h/skdrv2nd.h"
+#include "h/skgepnm2.h"
+#ifdef SK_POWER_MGMT
+#include "h/skgepmgt.h"
+#endif
+/* defines *******************************************************************/
+
+#ifndef DEBUG
+#define PNMI_STATIC    static
+#else  /* DEBUG */
+#define PNMI_STATIC
+#endif /* DEBUG */
+
+/*
+ * Public Function prototypes
+ */
+int SkPnmiInit(SK_AC *pAC, SK_IOC IoC, int level);
+int SkPnmiSetVar(SK_AC *pAC, SK_IOC IoC, SK_U32 Id, void *pBuf,
+       unsigned int *pLen, SK_U32 Instance, SK_U32 NetIndex);
+int SkPnmiGetStruct(SK_AC *pAC, SK_IOC IoC, void *pBuf,
+       unsigned int *pLen, SK_U32 NetIndex);
+int SkPnmiPreSetStruct(SK_AC *pAC, SK_IOC IoC, void *pBuf,
+       unsigned int *pLen, SK_U32 NetIndex);
+int SkPnmiSetStruct(SK_AC *pAC, SK_IOC IoC, void *pBuf,
+       unsigned int *pLen, SK_U32 NetIndex);
+int SkPnmiEvent(SK_AC *pAC, SK_IOC IoC, SK_U32 Event, SK_EVPARA Param);
+int SkPnmiGenIoctl(SK_AC *pAC, SK_IOC IoC, void * pBuf,
+       unsigned int * pLen, SK_U32 NetIndex);
+
+
+/*
+ * Private Function prototypes
+ */
+
+PNMI_STATIC SK_U8 CalculateLinkModeStatus(SK_AC *pAC, SK_IOC IoC, unsigned int
+       PhysPortIndex);
+PNMI_STATIC SK_U8 CalculateLinkStatus(SK_AC *pAC, SK_IOC IoC, unsigned int
+       PhysPortIndex);
+PNMI_STATIC void CopyMac(char *pDst, SK_MAC_ADDR *pMac);
+PNMI_STATIC void CopyTrapQueue(SK_AC *pAC, char *pDstBuf);
+PNMI_STATIC SK_U64 GetPhysStatVal(SK_AC *pAC, SK_IOC IoC,
+       unsigned int PhysPortIndex, unsigned int StatIndex);
+PNMI_STATIC SK_U64 GetStatVal(SK_AC *pAC, SK_IOC IoC, unsigned int LogPortIndex,
+       unsigned int StatIndex, SK_U32 NetIndex);
+PNMI_STATIC char* GetTrapEntry(SK_AC *pAC, SK_U32 TrapId, unsigned int Size);
+PNMI_STATIC void GetTrapQueueLen(SK_AC *pAC, unsigned int *pLen,
+       unsigned int *pEntries);
+PNMI_STATIC int GetVpdKeyArr(SK_AC *pAC, SK_IOC IoC, char *pKeyArr,
+       unsigned int KeyArrLen, unsigned int *pKeyNo);
+PNMI_STATIC int LookupId(SK_U32 Id);
+PNMI_STATIC int MacUpdate(SK_AC *pAC, SK_IOC IoC, unsigned int FirstMac,
+       unsigned int LastMac);
+PNMI_STATIC int PnmiStruct(SK_AC *pAC, SK_IOC IoC, int Action, char *pBuf,
+       unsigned int *pLen, SK_U32 NetIndex);
+PNMI_STATIC int PnmiVar(SK_AC *pAC, SK_IOC IoC, int Action, SK_U32 Id,
+       char *pBuf, unsigned int *pLen, SK_U32 Instance, SK_U32 NetIndex);
+PNMI_STATIC void QueueRlmtNewMacTrap(SK_AC *pAC, unsigned int ActiveMac);
+PNMI_STATIC void QueueRlmtPortTrap(SK_AC *pAC, SK_U32 TrapId,
+       unsigned int PortIndex);
+PNMI_STATIC void QueueSensorTrap(SK_AC *pAC, SK_U32 TrapId,
+       unsigned int SensorIndex);
+PNMI_STATIC void QueueSimpleTrap(SK_AC *pAC, SK_U32 TrapId);
+PNMI_STATIC void ResetCounter(SK_AC *pAC, SK_IOC IoC, SK_U32 NetIndex);
+PNMI_STATIC int RlmtUpdate(SK_AC *pAC, SK_IOC IoC, SK_U32 NetIndex);
+PNMI_STATIC int SirqUpdate(SK_AC *pAC, SK_IOC IoC);
+PNMI_STATIC void VirtualConf(SK_AC *pAC, SK_IOC IoC, SK_U32 Id, char *pBuf);
+PNMI_STATIC int Vct(SK_AC *pAC, SK_IOC IoC, int Action, SK_U32 Id, char *pBuf,
+       unsigned int *pLen, SK_U32 Instance, unsigned int TableIndex, SK_U32 NetIndex);
+PNMI_STATIC void CheckVctStatus(SK_AC *, SK_IOC, char *, SK_U32, SK_U32);
+
+/*
+ * Table to correlate OID with handler function and index to
+ * hardware register stored in StatAddress if applicable.
+ */
+#include "skgemib.c"
+
+/* global variables **********************************************************/
+
+/*
+ * Overflow status register bit table and corresponding counter
+ * dependent on MAC type - the number relates to the size of overflow
+ * mask returned by the pFnMacOverflow function
+ */
+PNMI_STATIC const SK_U16 StatOvrflwBit[][SK_PNMI_MAC_TYPES] = {
+/* Bit0  */    { SK_PNMI_HTX,                          SK_PNMI_HTX_UNICAST},
+/* Bit1  */    { SK_PNMI_HTX_OCTETHIGH,        SK_PNMI_HTX_BROADCAST},
+/* Bit2  */    { SK_PNMI_HTX_OCTETLOW,         SK_PNMI_HTX_PMACC},
+/* Bit3  */    { SK_PNMI_HTX_BROADCAST,        SK_PNMI_HTX_MULTICAST},
+/* Bit4  */    { SK_PNMI_HTX_MULTICAST,        SK_PNMI_HTX_OCTETLOW},
+/* Bit5  */    { SK_PNMI_HTX_UNICAST,          SK_PNMI_HTX_OCTETHIGH},
+/* Bit6  */    { SK_PNMI_HTX_LONGFRAMES,       SK_PNMI_HTX_64},
+/* Bit7  */    { SK_PNMI_HTX_BURST,            SK_PNMI_HTX_127},
+/* Bit8  */    { SK_PNMI_HTX_PMACC,            SK_PNMI_HTX_255},
+/* Bit9  */    { SK_PNMI_HTX_MACC,             SK_PNMI_HTX_511},
+/* Bit10 */    { SK_PNMI_HTX_SINGLE_COL,       SK_PNMI_HTX_1023},
+/* Bit11 */    { SK_PNMI_HTX_MULTI_COL,        SK_PNMI_HTX_MAX},
+/* Bit12 */    { SK_PNMI_HTX_EXCESS_COL,       SK_PNMI_HTX_LONGFRAMES},
+/* Bit13 */    { SK_PNMI_HTX_LATE_COL,         SK_PNMI_HTX_RESERVED},
+/* Bit14 */    { SK_PNMI_HTX_DEFFERAL,         SK_PNMI_HTX_COL},
+/* Bit15 */    { SK_PNMI_HTX_EXCESS_DEF,       SK_PNMI_HTX_LATE_COL},
+/* Bit16 */    { SK_PNMI_HTX_UNDERRUN,         SK_PNMI_HTX_EXCESS_COL},
+/* Bit17 */    { SK_PNMI_HTX_CARRIER,          SK_PNMI_HTX_MULTI_COL},
+/* Bit18 */    { SK_PNMI_HTX_UTILUNDER,        SK_PNMI_HTX_SINGLE_COL},
+/* Bit19 */    { SK_PNMI_HTX_UTILOVER,         SK_PNMI_HTX_UNDERRUN},
+/* Bit20 */    { SK_PNMI_HTX_64,                       SK_PNMI_HTX_RESERVED},
+/* Bit21 */    { SK_PNMI_HTX_127,                      SK_PNMI_HTX_RESERVED},
+/* Bit22 */    { SK_PNMI_HTX_255,                      SK_PNMI_HTX_RESERVED},
+/* Bit23 */    { SK_PNMI_HTX_511,                      SK_PNMI_HTX_RESERVED},
+/* Bit24 */    { SK_PNMI_HTX_1023,             SK_PNMI_HTX_RESERVED},
+/* Bit25 */    { SK_PNMI_HTX_MAX,                      SK_PNMI_HTX_RESERVED},
+/* Bit26 */    { SK_PNMI_HTX_RESERVED,         SK_PNMI_HTX_RESERVED},
+/* Bit27 */    { SK_PNMI_HTX_RESERVED,         SK_PNMI_HTX_RESERVED},
+/* Bit28 */    { SK_PNMI_HTX_RESERVED,         SK_PNMI_HTX_RESERVED},
+/* Bit29 */    { SK_PNMI_HTX_RESERVED,         SK_PNMI_HTX_RESERVED},
+/* Bit30 */    { SK_PNMI_HTX_RESERVED,         SK_PNMI_HTX_RESERVED},
+/* Bit31 */    { SK_PNMI_HTX_RESERVED,         SK_PNMI_HTX_RESERVED},
+/* Bit32 */    { SK_PNMI_HRX,                          SK_PNMI_HRX_UNICAST},
+/* Bit33 */    { SK_PNMI_HRX_OCTETHIGH,        SK_PNMI_HRX_BROADCAST},
+/* Bit34 */    { SK_PNMI_HRX_OCTETLOW,         SK_PNMI_HRX_PMACC},
+/* Bit35 */    { SK_PNMI_HRX_BROADCAST,        SK_PNMI_HRX_MULTICAST},
+/* Bit36 */    { SK_PNMI_HRX_MULTICAST,        SK_PNMI_HRX_FCS},
+/* Bit37 */    { SK_PNMI_HRX_UNICAST,          SK_PNMI_HRX_RESERVED},
+/* Bit38 */    { SK_PNMI_HRX_PMACC,            SK_PNMI_HRX_OCTETLOW},
+/* Bit39 */    { SK_PNMI_HRX_MACC,             SK_PNMI_HRX_OCTETHIGH},
+/* Bit40 */    { SK_PNMI_HRX_PMACC_ERR,        SK_PNMI_HRX_BADOCTETLOW},
+/* Bit41 */    { SK_PNMI_HRX_MACC_UNKWN,       SK_PNMI_HRX_BADOCTETHIGH},
+/* Bit42 */    { SK_PNMI_HRX_BURST,            SK_PNMI_HRX_UNDERSIZE},
+/* Bit43 */    { SK_PNMI_HRX_MISSED,           SK_PNMI_HRX_RUNT},
+/* Bit44 */    { SK_PNMI_HRX_FRAMING,          SK_PNMI_HRX_64},
+/* Bit45 */    { SK_PNMI_HRX_OVERFLOW,         SK_PNMI_HRX_127},
+/* Bit46 */    { SK_PNMI_HRX_JABBER,           SK_PNMI_HRX_255},
+/* Bit47 */    { SK_PNMI_HRX_CARRIER,          SK_PNMI_HRX_511},
+/* Bit48 */    { SK_PNMI_HRX_IRLENGTH,         SK_PNMI_HRX_1023},
+/* Bit49 */    { SK_PNMI_HRX_SYMBOL,           SK_PNMI_HRX_MAX},
+/* Bit50 */    { SK_PNMI_HRX_SHORTS,           SK_PNMI_HRX_LONGFRAMES},
+/* Bit51 */    { SK_PNMI_HRX_RUNT,             SK_PNMI_HRX_TOO_LONG},
+/* Bit52 */    { SK_PNMI_HRX_TOO_LONG,         SK_PNMI_HRX_JABBER},
+/* Bit53 */    { SK_PNMI_HRX_FCS,                      SK_PNMI_HRX_RESERVED},
+/* Bit54 */    { SK_PNMI_HRX_RESERVED,         SK_PNMI_HRX_OVERFLOW},
+/* Bit55 */    { SK_PNMI_HRX_CEXT,             SK_PNMI_HRX_RESERVED},
+/* Bit56 */    { SK_PNMI_HRX_UTILUNDER,        SK_PNMI_HRX_RESERVED},
+/* Bit57 */    { SK_PNMI_HRX_UTILOVER,         SK_PNMI_HRX_RESERVED},
+/* Bit58 */    { SK_PNMI_HRX_64,                       SK_PNMI_HRX_RESERVED},
+/* Bit59 */    { SK_PNMI_HRX_127,                      SK_PNMI_HRX_RESERVED},
+/* Bit60 */    { SK_PNMI_HRX_255,                      SK_PNMI_HRX_RESERVED},
+/* Bit61 */    { SK_PNMI_HRX_511,                      SK_PNMI_HRX_RESERVED},
+/* Bit62 */    { SK_PNMI_HRX_1023,             SK_PNMI_HRX_RESERVED},
+/* Bit63 */    { SK_PNMI_HRX_MAX,                      SK_PNMI_HRX_RESERVED}
+};
+
+/*
+ * Table for hardware register saving on resets and port switches
+ */
+PNMI_STATIC const SK_PNMI_STATADDR StatAddr[SK_PNMI_MAX_IDX][SK_PNMI_MAC_TYPES] = {
+       /* SK_PNMI_HTX */
+       {{XM_TXF_OK, SK_TRUE}, {0, SK_FALSE}},
+       /* SK_PNMI_HTX_OCTETHIGH */
+       {{XM_TXO_OK_HI, SK_TRUE}, {GM_TXO_OK_HI, SK_TRUE}},
+       /* SK_PNMI_HTX_OCTETLOW */
+       {{XM_TXO_OK_LO, SK_FALSE}, {GM_TXO_OK_LO, SK_FALSE}},
+       /* SK_PNMI_HTX_BROADCAST */
+       {{XM_TXF_BC_OK, SK_TRUE}, {GM_TXF_BC_OK, SK_TRUE}},
+       /* SK_PNMI_HTX_MULTICAST */
+       {{XM_TXF_MC_OK, SK_TRUE}, {GM_TXF_MC_OK, SK_TRUE}},
+       /* SK_PNMI_HTX_UNICAST */
+       {{XM_TXF_UC_OK, SK_TRUE}, {GM_TXF_UC_OK, SK_TRUE}},
+       /* SK_PNMI_HTX_BURST */
+       {{XM_TXE_BURST, SK_TRUE}, {0, SK_FALSE}},
+       /* SK_PNMI_HTX_PMACC */
+       {{XM_TXF_MPAUSE, SK_TRUE}, {GM_TXF_MPAUSE, SK_TRUE}},
+       /* SK_PNMI_HTX_MACC */
+       {{XM_TXF_MCTRL, SK_TRUE}, {0, SK_FALSE}},
+       /* SK_PNMI_HTX_COL */
+       {{0, SK_FALSE}, {GM_TXF_COL, SK_TRUE}},
+       /* SK_PNMI_HTX_SINGLE_COL */
+       {{XM_TXF_SNG_COL, SK_TRUE}, {GM_TXF_SNG_COL, SK_TRUE}},
+       /* SK_PNMI_HTX_MULTI_COL */
+       {{XM_TXF_MUL_COL, SK_TRUE}, {GM_TXF_MUL_COL, SK_TRUE}},
+       /* SK_PNMI_HTX_EXCESS_COL */
+       {{XM_TXF_ABO_COL, SK_TRUE}, {GM_TXF_ABO_COL, SK_TRUE}},
+       /* SK_PNMI_HTX_LATE_COL */
+       {{XM_TXF_LAT_COL, SK_TRUE}, {GM_TXF_LAT_COL, SK_TRUE}},
+       /* SK_PNMI_HTX_DEFFERAL */
+       {{XM_TXF_DEF, SK_TRUE}, {0, SK_FALSE}},
+       /* SK_PNMI_HTX_EXCESS_DEF */
+       {{XM_TXF_EX_DEF, SK_TRUE}, {0, SK_FALSE}},
+       /* SK_PNMI_HTX_UNDERRUN */
+       {{XM_TXE_FIFO_UR, SK_TRUE}, {GM_TXE_FIFO_UR, SK_TRUE}},
+       /* SK_PNMI_HTX_CARRIER */
+       {{XM_TXE_CS_ERR, SK_TRUE}, {0, SK_FALSE}},
+       /* SK_PNMI_HTX_UTILUNDER */
+       {{0, SK_FALSE}, {0, SK_FALSE}},
+       /* SK_PNMI_HTX_UTILOVER */
+       {{0, SK_FALSE}, {0, SK_FALSE}},
+       /* SK_PNMI_HTX_64 */
+       {{XM_TXF_64B, SK_TRUE}, {GM_TXF_64B, SK_TRUE}},
+       /* SK_PNMI_HTX_127 */
+       {{XM_TXF_127B, SK_TRUE}, {GM_TXF_127B, SK_TRUE}},
+       /* SK_PNMI_HTX_255 */
+       {{XM_TXF_255B, SK_TRUE}, {GM_TXF_255B, SK_TRUE}},
+       /* SK_PNMI_HTX_511 */
+       {{XM_TXF_511B, SK_TRUE}, {GM_TXF_511B, SK_TRUE}},
+       /* SK_PNMI_HTX_1023 */
+       {{XM_TXF_1023B, SK_TRUE}, {GM_TXF_1023B, SK_TRUE}},
+       /* SK_PNMI_HTX_MAX */
+       {{XM_TXF_MAX_SZ, SK_TRUE}, {GM_TXF_1518B, SK_TRUE}},
+       /* SK_PNMI_HTX_LONGFRAMES  */
+       {{XM_TXF_LONG, SK_TRUE}, {GM_TXF_MAX_SZ, SK_TRUE}},
+       /* SK_PNMI_HTX_SYNC */
+       {{0, SK_FALSE}, {0, SK_FALSE}},
+       /* SK_PNMI_HTX_SYNC_OCTET */
+       {{0, SK_FALSE}, {0, SK_FALSE}},
+       /* SK_PNMI_HTX_RESERVED */
+       {{0, SK_FALSE}, {0, SK_FALSE}},
+       /* SK_PNMI_HRX */
+       {{XM_RXF_OK, SK_TRUE}, {0, SK_FALSE}},
+       /* SK_PNMI_HRX_OCTETHIGH */
+       {{XM_RXO_OK_HI, SK_TRUE}, {GM_RXO_OK_HI, SK_TRUE}},
+       /* SK_PNMI_HRX_OCTETLOW */
+       {{XM_RXO_OK_LO, SK_FALSE}, {GM_RXO_OK_LO, SK_FALSE}},
+       /* SK_PNMI_HRX_BADOCTETHIGH */
+       {{0, SK_FALSE}, {GM_RXO_ERR_HI, SK_TRUE}},
+       /* SK_PNMI_HRX_BADOCTETLOW */
+       {{0, SK_FALSE}, {GM_RXO_ERR_LO, SK_TRUE}},
+       /* SK_PNMI_HRX_BROADCAST */
+       {{XM_RXF_BC_OK, SK_TRUE}, {GM_RXF_BC_OK, SK_TRUE}},
+       /* SK_PNMI_HRX_MULTICAST */
+       {{XM_RXF_MC_OK, SK_TRUE}, {GM_RXF_MC_OK, SK_TRUE}},
+       /* SK_PNMI_HRX_UNICAST */
+       {{XM_RXF_UC_OK, SK_TRUE}, {GM_RXF_UC_OK, SK_TRUE}},
+       /* SK_PNMI_HRX_PMACC */
+       {{XM_RXF_MPAUSE, SK_TRUE}, {GM_RXF_MPAUSE, SK_TRUE}},
+       /* SK_PNMI_HRX_MACC */
+       {{XM_RXF_MCTRL, SK_TRUE}, {0, SK_FALSE}},
+       /* SK_PNMI_HRX_PMACC_ERR */
+       {{XM_RXF_INV_MP, SK_TRUE}, {0, SK_FALSE}},
+       /* SK_PNMI_HRX_MACC_UNKWN */
+       {{XM_RXF_INV_MOC, SK_TRUE}, {0, SK_FALSE}},
+       /* SK_PNMI_HRX_BURST */
+       {{XM_RXE_BURST, SK_TRUE}, {0, SK_FALSE}},
+       /* SK_PNMI_HRX_MISSED */
+       {{XM_RXE_FMISS, SK_TRUE}, {0, SK_FALSE}},
+       /* SK_PNMI_HRX_FRAMING */
+       {{XM_RXF_FRA_ERR, SK_TRUE}, {0, SK_FALSE}},
+       /* SK_PNMI_HRX_UNDERSIZE */
+       {{0, SK_FALSE}, {GM_RXF_SHT, SK_TRUE}},
+       /* SK_PNMI_HRX_OVERFLOW */
+       {{XM_RXE_FIFO_OV, SK_TRUE}, {GM_RXE_FIFO_OV, SK_TRUE}},
+       /* SK_PNMI_HRX_JABBER */
+       {{XM_RXF_JAB_PKT, SK_TRUE}, {GM_RXF_JAB_PKT, SK_TRUE}},
+       /* SK_PNMI_HRX_CARRIER */
+       {{XM_RXE_CAR_ERR, SK_TRUE}, {0, SK_FALSE}},
+       /* SK_PNMI_HRX_IRLENGTH */
+       {{XM_RXF_LEN_ERR, SK_TRUE}, {0, SK_FALSE}},
+       /* SK_PNMI_HRX_SYMBOL */
+       {{XM_RXE_SYM_ERR, SK_TRUE}, {0, SK_FALSE}},
+       /* SK_PNMI_HRX_SHORTS */
+       {{XM_RXE_SHT_ERR, SK_TRUE}, {0, SK_FALSE}},
+       /* SK_PNMI_HRX_RUNT */
+       {{XM_RXE_RUNT, SK_TRUE}, {GM_RXE_FRAG, SK_TRUE}},
+       /* SK_PNMI_HRX_TOO_LONG */
+       {{XM_RXF_LNG_ERR, SK_TRUE}, {GM_RXF_LNG_ERR, SK_TRUE}},
+       /* SK_PNMI_HRX_FCS */
+       {{XM_RXF_FCS_ERR, SK_TRUE}, {GM_RXF_FCS_ERR, SK_TRUE}},
+       /* SK_PNMI_HRX_CEXT */
+       {{XM_RXF_CEX_ERR, SK_TRUE}, {0, SK_FALSE}},
+       /* SK_PNMI_HRX_UTILUNDER */
+       {{0, SK_FALSE}, {0, SK_FALSE}},
+       /* SK_PNMI_HRX_UTILOVER */
+       {{0, SK_FALSE}, {0, SK_FALSE}},
+       /* SK_PNMI_HRX_64 */
+       {{XM_RXF_64B, SK_TRUE}, {GM_RXF_64B, SK_TRUE}},
+       /* SK_PNMI_HRX_127 */
+       {{XM_RXF_127B, SK_TRUE}, {GM_RXF_127B, SK_TRUE}},
+       /* SK_PNMI_HRX_255 */
+       {{XM_RXF_255B, SK_TRUE}, {GM_RXF_255B, SK_TRUE}},
+       /* SK_PNMI_HRX_511 */
+       {{XM_RXF_511B, SK_TRUE}, {GM_RXF_511B, SK_TRUE}},
+       /* SK_PNMI_HRX_1023 */
+       {{XM_RXF_1023B, SK_TRUE}, {GM_RXF_1023B, SK_TRUE}},
+       /* SK_PNMI_HRX_MAX */
+       {{XM_RXF_MAX_SZ, SK_TRUE}, {GM_RXF_1518B, SK_TRUE}},
+       /* SK_PNMI_HRX_LONGFRAMES */
+       {{0, SK_FALSE}, {GM_RXF_MAX_SZ, SK_TRUE}},
+       /* SK_PNMI_HRX_RESERVED */
+       {{0, SK_FALSE}, {0, SK_FALSE}}
+};
+
+
+/*****************************************************************************
+ *
+ * Public functions
+ *
+ */
+
+/*****************************************************************************
+ *
+ * SkPnmiInit - Init function of PNMI
+ *
+ * Description:
+ *     SK_INIT_DATA: Initialises the data structures
+ *     SK_INIT_IO:   Resets the XMAC statistics, determines the device and
+ *                   connector type.
+ *     SK_INIT_RUN:  Starts a timer event for port switch per hour
+ *                   calculation.
+ *
+ * Returns:
+ *     Always 0
+ */
+int SkPnmiInit(
+SK_AC *pAC,            /* Pointer to adapter context */
+SK_IOC IoC,            /* IO context handle */
+int Level)             /* Initialization level */
+{
+       unsigned int    PortMax;        /* Number of ports */
+       unsigned int    PortIndex;      /* Current port index in loop */
+       SK_U16          Val16;          /* Multiple purpose 16 bit variable */
+       SK_U8           Val8;           /* Mulitple purpose 8 bit variable */
+       SK_EVPARA       EventParam;     /* Event struct for timer event */
+       SK_PNMI_VCT     *pVctBackupData;
+
+
+       SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_CTRL,
+               ("PNMI: SkPnmiInit: Called, level=%d\n", Level));
+
+       switch (Level) {
+
+       case SK_INIT_DATA:
+               SK_MEMSET((char *)&pAC->Pnmi, 0, sizeof(pAC->Pnmi));
+               pAC->Pnmi.TrapBufFree = SK_PNMI_TRAP_QUEUE_LEN;
+               pAC->Pnmi.StartUpTime = SK_PNMI_HUNDREDS_SEC(SkOsGetTime(pAC));
+               pAC->Pnmi.RlmtChangeThreshold = SK_PNMI_DEF_RLMT_CHG_THRES;
+               for (PortIndex = 0; PortIndex < SK_MAX_MACS; PortIndex ++) {
+
+                       pAC->Pnmi.Port[PortIndex].ActiveFlag = SK_FALSE;
+                       pAC->Pnmi.DualNetActiveFlag = SK_FALSE;
+               }
+
+#ifdef SK_PNMI_CHECK
+               if (SK_PNMI_MAX_IDX != SK_PNMI_CNT_NO) {
+                       
+                       SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR049, SK_PNMI_ERR049MSG);
+
+                       SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_INIT | SK_DBGCAT_FATAL,
+                                          ("CounterOffset struct size (%d) differs from"
+                                               "SK_PNMI_MAX_IDX (%d)\n",
+                                               SK_PNMI_CNT_NO, SK_PNMI_MAX_IDX));
+               }
+
+               if (SK_PNMI_MAX_IDX !=
+                       (sizeof(StatAddr) / (sizeof(SK_PNMI_STATADDR) * SK_PNMI_MAC_TYPES))) {
+                       
+                       SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR050, SK_PNMI_ERR050MSG);
+
+                       SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_INIT | SK_DBGCAT_FATAL,
+                                          ("StatAddr table size (%d) differs from "
+                                               "SK_PNMI_MAX_IDX (%d)\n",
+                                               (sizeof(StatAddr) /
+                                                (sizeof(SK_PNMI_STATADDR) * SK_PNMI_MAC_TYPES)),
+                                                SK_PNMI_MAX_IDX));
+               }
+#endif /* SK_PNMI_CHECK */
+               break;
+
+       case SK_INIT_IO:
+               /*
+                * Reset MAC counters
+                */
+               PortMax = pAC->GIni.GIMacsFound;
+
+               for (PortIndex = 0; PortIndex < PortMax; PortIndex ++) {
+
+                       pAC->GIni.GIFunc.pFnMacResetCounter(pAC, IoC, PortIndex);
+               }
+               
+               /* Initialize DSP variables for Vct() to 0xff => Never written! */              
+               for (PortIndex = 0; PortIndex < PortMax; PortIndex ++) {
+                       pAC->GIni.GP[PortIndex].PCableLen = 0xff;
+                       pVctBackupData = &pAC->Pnmi.VctBackup[PortIndex];
+                       pVctBackupData->PCableLen = 0xff;
+               }
+               
+               /*
+                * Get pci bus speed
+                */
+               SK_IN16(IoC, B0_CTST, &Val16);
+               if ((Val16 & CS_BUS_CLOCK) == 0) {
+
+                       pAC->Pnmi.PciBusSpeed = 33;
+               }
+               else {
+                       pAC->Pnmi.PciBusSpeed = 66;
+               }
+
+               /*
+                * Get pci bus width
+                */
+               SK_IN16(IoC, B0_CTST, &Val16);
+               if ((Val16 & CS_BUS_SLOT_SZ) == 0) {
+
+                       pAC->Pnmi.PciBusWidth = 32;
+               }
+               else {
+                       pAC->Pnmi.PciBusWidth = 64;
+               }
+
+               /*
+                * Get chipset
+                */
+               switch (pAC->GIni.GIChipId) {
+               case CHIP_ID_GENESIS:
+                       pAC->Pnmi.Chipset = SK_PNMI_CHIPSET_XMAC;
+                       break;
+
+               case CHIP_ID_YUKON:
+                       pAC->Pnmi.Chipset = SK_PNMI_CHIPSET_YUKON;
+                       break;
+
+               default:
+                       break;
+               }
+
+               /*
+                * Get PMD and DeviceType
+                */
+               SK_IN8(IoC, B2_PMD_TYP, &Val8);
+               switch (Val8) {
+               case 'S':
+                       pAC->Pnmi.PMD = 3;
+                       if (pAC->GIni.GIMacsFound > 1) {
+
+                               pAC->Pnmi.DeviceType = 0x00020002;
+                       }
+                       else {
+                               pAC->Pnmi.DeviceType = 0x00020001;
+                       }
+                       break;
+
+               case 'L':
+                       pAC->Pnmi.PMD = 2;
+                       if (pAC->GIni.GIMacsFound > 1) {
+
+                               pAC->Pnmi.DeviceType = 0x00020004;
+                       }
+                       else {
+                               pAC->Pnmi.DeviceType = 0x00020003;
+                       }
+                       break;
+
+               case 'C':
+                       pAC->Pnmi.PMD = 4;
+                       if (pAC->GIni.GIMacsFound > 1) {
+
+                               pAC->Pnmi.DeviceType = 0x00020006;
+                       }
+                       else {
+                               pAC->Pnmi.DeviceType = 0x00020005;
+                       }
+                       break;
+
+               case 'T':
+                       pAC->Pnmi.PMD = 5;
+                       if (pAC->GIni.GIMacsFound > 1) {
+
+                               pAC->Pnmi.DeviceType = 0x00020008;
+                       }
+                       else {
+                               pAC->Pnmi.DeviceType = 0x00020007;
+                       }
+                       break;
+
+               default :
+                       pAC->Pnmi.PMD = 1;
+                       pAC->Pnmi.DeviceType = 0;
+                       break;
+               }
+
+               /*
+                * Get connector
+                */
+               SK_IN8(IoC, B2_CONN_TYP, &Val8);
+               switch (Val8) {
+               case 'C':
+                       pAC->Pnmi.Connector = 2;
+                       break;
+
+               case 'D':
+                       pAC->Pnmi.Connector = 3;
+                       break;
+
+               case 'F':
+                       pAC->Pnmi.Connector = 4;
+                       break;
+
+               case 'J':
+                       pAC->Pnmi.Connector = 5;
+                       break;
+
+               case 'V':
+                       pAC->Pnmi.Connector = 6;
+                       break;
+
+               default:
+                       pAC->Pnmi.Connector = 1;
+                       break;
+               }
+               break;
+
+       case SK_INIT_RUN:
+               /*
+                * Start timer for RLMT change counter
+                */
+               SK_MEMSET((char *)&EventParam, 0, sizeof(EventParam));
+               SkTimerStart(pAC, IoC, &pAC->Pnmi.RlmtChangeEstimate.EstTimer,
+                       28125000, SKGE_PNMI, SK_PNMI_EVT_CHG_EST_TIMER,
+                       EventParam);
+               break;
+
+       default:
+               break; /* Nothing todo */
+       }
+
+       return (0);
+}
+
+/*****************************************************************************
+ *
+ * SkPnmiGetVar - Retrieves the value of a single OID
+ *
+ * Description:
+ *     Calls a general sub-function for all this stuff. If the instance
+ *     -1 is passed, the values of all instances are returned in an
+ *     array of values.
+ *
+ * Returns:
+ *     SK_PNMI_ERR_OK           The request was successfully performed
+ *     SK_PNMI_ERR_GENERAL      A general severe internal error occured
+ *     SK_PNMI_ERR_TOO_SHORT    The passed buffer is too short to take
+ *                              the data.
+ *     SK_PNMI_ERR_UNKNOWN_OID  The requested OID is unknown
+ *     SK_PNMI_ERR_UNKNOWN_INST The requested instance of the OID doesn't
+ *                           exist (e.g. port instance 3 on a two port
+ *                              adapter.
+ */
+static int SkPnmiGetVar(
+SK_AC *pAC,            /* Pointer to adapter context */
+SK_IOC IoC,            /* IO context handle */
+SK_U32 Id,             /* Object ID that is to be processed */
+void *pBuf,            /* Buffer to which the management data will be copied */
+unsigned int *pLen,    /* On call: buffer length. On return: used buffer */
+SK_U32 Instance,       /* Instance (1..n) that is to be queried or -1 */
+SK_U32 NetIndex)       /* NetIndex (0..n), in single net mode always zero */
+{
+       SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_CTRL,
+               ("PNMI: SkPnmiGetVar: Called, Id=0x%x, BufLen=%d, Instance=%d, NetIndex=%d\n",
+                       Id, *pLen, Instance, NetIndex));
+
+       return (PnmiVar(pAC, IoC, SK_PNMI_GET, Id, (char *)pBuf, pLen,
+               Instance, NetIndex));
+}
+
+/*****************************************************************************
+ *
+ * SkPnmiPreSetVar - Presets the value of a single OID
+ *
+ * Description:
+ *     Calls a general sub-function for all this stuff. The preset does
+ *     the same as a set, but returns just before finally setting the
+ *     new value. This is useful to check if a set might be successfull.
+ *     If the instance -1 is passed, an array of values is supposed and
+ *     all instances of the OID will be set.
+ *
+ * Returns:
+ *     SK_PNMI_ERR_OK           The request was successfully performed.
+ *     SK_PNMI_ERR_GENERAL      A general severe internal error occured.
+ *     SK_PNMI_ERR_TOO_SHORT    The passed buffer is too short to contain
+ *                              the correct data (e.g. a 32bit value is
+ *                              needed, but a 16 bit value was passed).
+ *     SK_PNMI_ERR_BAD_VALUE    The passed value is not in the valid
+ *                              value range.
+ *     SK_PNMI_ERR_READ_ONLY    The OID is read-only and cannot be set.
+ *     SK_PNMI_ERR_UNKNOWN_OID  The requested OID is unknown.
+ *     SK_PNMI_ERR_UNKNOWN_INST The requested instance of the OID doesn't
+ *                           exist (e.g. port instance 3 on a two port
+ *                              adapter.
+ */
+static int SkPnmiPreSetVar(
+SK_AC *pAC,            /* Pointer to adapter context */
+SK_IOC IoC,            /* IO context handle */
+SK_U32 Id,             /* Object ID that is to be processed */
+void *pBuf,            /* Buffer to which the management data will be copied */
+unsigned int *pLen,    /* Total length of management data */
+SK_U32 Instance,       /* Instance (1..n) that is to be set or -1 */
+SK_U32 NetIndex)       /* NetIndex (0..n), in single net mode always zero */
+{
+       SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_CTRL,
+               ("PNMI: SkPnmiPreSetVar: Called, Id=0x%x, BufLen=%d, Instance=%d, NetIndex=%d\n",
+                       Id, *pLen, Instance, NetIndex));
+
+
+       return (PnmiVar(pAC, IoC, SK_PNMI_PRESET, Id, (char *)pBuf, pLen,
+               Instance, NetIndex));
+}
+
+/*****************************************************************************
+ *
+ * SkPnmiSetVar - Sets the value of a single OID
+ *
+ * Description:
+ *     Calls a general sub-function for all this stuff. The preset does
+ *     the same as a set, but returns just before finally setting the
+ *     new value. This is useful to check if a set might be successfull.
+ *     If the instance -1 is passed, an array of values is supposed and
+ *     all instances of the OID will be set.
+ *
+ * Returns:
+ *     SK_PNMI_ERR_OK           The request was successfully performed.
+ *     SK_PNMI_ERR_GENERAL      A general severe internal error occured.
+ *     SK_PNMI_ERR_TOO_SHORT    The passed buffer is too short to contain
+ *                              the correct data (e.g. a 32bit value is
+ *                              needed, but a 16 bit value was passed).
+ *     SK_PNMI_ERR_BAD_VALUE    The passed value is not in the valid
+ *                              value range.
+ *     SK_PNMI_ERR_READ_ONLY    The OID is read-only and cannot be set.
+ *     SK_PNMI_ERR_UNKNOWN_OID  The requested OID is unknown.
+ *     SK_PNMI_ERR_UNKNOWN_INST The requested instance of the OID doesn't
+ *                           exist (e.g. port instance 3 on a two port
+ *                              adapter.
+ */
+int SkPnmiSetVar(
+SK_AC *pAC,            /* Pointer to adapter context */
+SK_IOC IoC,            /* IO context handle */
+SK_U32 Id,             /* Object ID that is to be processed */
+void *pBuf,            /* Buffer to which the management data will be copied */
+unsigned int *pLen,    /* Total length of management data */
+SK_U32 Instance,       /* Instance (1..n) that is to be set or -1 */
+SK_U32 NetIndex)       /* NetIndex (0..n), in single net mode always zero */
+{
+       SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_CTRL,
+               ("PNMI: SkPnmiSetVar: Called, Id=0x%x, BufLen=%d, Instance=%d, NetIndex=%d\n",
+                       Id, *pLen, Instance, NetIndex));
+
+       return (PnmiVar(pAC, IoC, SK_PNMI_SET, Id, (char *)pBuf, pLen,
+               Instance, NetIndex));
+}
+
+/*****************************************************************************
+ *
+ * SkPnmiGetStruct - Retrieves the management database in SK_PNMI_STRUCT_DATA
+ *
+ * Description:
+ *     Runs through the IdTable, queries the single OIDs and stores the
+ *     returned data into the management database structure
+ *     SK_PNMI_STRUCT_DATA. The offset of the OID in the structure
+ *     is stored in the IdTable. The return value of the function will also
+ *     be stored in SK_PNMI_STRUCT_DATA if the passed buffer has the
+ *     minimum size of SK_PNMI_MIN_STRUCT_SIZE.
+ *
+ * Returns:
+ *     SK_PNMI_ERR_OK           The request was successfully performed
+ *     SK_PNMI_ERR_GENERAL      A general severe internal error occured
+ *     SK_PNMI_ERR_TOO_SHORT    The passed buffer is too short to take
+ *                              the data.
+ *     SK_PNMI_ERR_UNKNOWN_NET  The requested NetIndex doesn't exist
+ */
+int SkPnmiGetStruct(
+SK_AC *pAC,            /* Pointer to adapter context */
+SK_IOC IoC,            /* IO context handle */
+void *pBuf,            /* Buffer to which the management data will be copied. */
+unsigned int *pLen,    /* Length of buffer */
+SK_U32 NetIndex)       /* NetIndex (0..n), in single net mode always zero */
+{
+       int             Ret;
+       unsigned int    TableIndex;
+       unsigned int    DstOffset;
+       unsigned int    InstanceNo;
+       unsigned int    InstanceCnt;
+       SK_U32          Instance;
+       unsigned int    TmpLen;
+       char            KeyArr[SK_PNMI_VPD_ENTRIES][SK_PNMI_VPD_KEY_SIZE];
+
+
+       SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_CTRL,
+               ("PNMI: SkPnmiGetStruct: Called, BufLen=%d, NetIndex=%d\n",
+                       *pLen, NetIndex));
+
+       if (*pLen < SK_PNMI_STRUCT_SIZE) {
+
+               if (*pLen >= SK_PNMI_MIN_STRUCT_SIZE) {
+
+                       SK_PNMI_SET_STAT(pBuf, SK_PNMI_ERR_TOO_SHORT,
+                               (SK_U32)(-1));
+               }
+
+               *pLen = SK_PNMI_STRUCT_SIZE;
+               return (SK_PNMI_ERR_TOO_SHORT);
+       }
+
+    /*
+     * Check NetIndex
+     */
+       if (NetIndex >= pAC->Rlmt.NumNets) {
+               return (SK_PNMI_ERR_UNKNOWN_NET);
+       }
+
+       /* Update statistic */
+       SK_PNMI_CHECKFLAGS("SkPnmiGetStruct: On call");
+
+       if ((Ret = MacUpdate(pAC, IoC, 0, pAC->GIni.GIMacsFound - 1)) !=
+               SK_PNMI_ERR_OK) {
+
+               SK_PNMI_SET_STAT(pBuf, Ret, (SK_U32)(-1));
+               *pLen = SK_PNMI_MIN_STRUCT_SIZE;
+               return (Ret);
+       }
+
+       if ((Ret = RlmtUpdate(pAC, IoC, NetIndex)) != SK_PNMI_ERR_OK) {
+
+               SK_PNMI_SET_STAT(pBuf, Ret, (SK_U32)(-1));
+               *pLen = SK_PNMI_MIN_STRUCT_SIZE;
+               return (Ret);
+       }
+
+       if ((Ret = SirqUpdate(pAC, IoC)) != SK_PNMI_ERR_OK) {
+
+               SK_PNMI_SET_STAT(pBuf, Ret, (SK_U32)(-1));
+               *pLen = SK_PNMI_MIN_STRUCT_SIZE;
+               return (Ret);
+       }
+
+       /*
+        * Increment semaphores to indicate that an update was
+        * already done
+        */
+       pAC->Pnmi.MacUpdatedFlag ++;
+       pAC->Pnmi.RlmtUpdatedFlag ++;
+       pAC->Pnmi.SirqUpdatedFlag ++;
+
+       /* Get vpd keys for instance calculation */
+       Ret = GetVpdKeyArr(pAC, IoC, &KeyArr[0][0], sizeof(KeyArr), &TmpLen);
+       if (Ret != SK_PNMI_ERR_OK) {
+
+               pAC->Pnmi.MacUpdatedFlag --;
+               pAC->Pnmi.RlmtUpdatedFlag --;
+               pAC->Pnmi.SirqUpdatedFlag --;
+
+               SK_PNMI_CHECKFLAGS("SkPnmiGetStruct: On return");
+               SK_PNMI_SET_STAT(pBuf, Ret, (SK_U32)(-1));
+               *pLen = SK_PNMI_MIN_STRUCT_SIZE;
+               return (SK_PNMI_ERR_GENERAL);
+       }
+
+       /* Retrieve values */
+       SK_MEMSET((char *)pBuf, 0, SK_PNMI_STRUCT_SIZE);
+       for (TableIndex = 0; TableIndex < ID_TABLE_SIZE; TableIndex ++) {
+
+               InstanceNo = IdTable[TableIndex].InstanceNo;
+               for (InstanceCnt = 1; InstanceCnt <= InstanceNo;
+                       InstanceCnt ++) {
+
+                       DstOffset = IdTable[TableIndex].Offset +
+                               (InstanceCnt - 1) *
+                               IdTable[TableIndex].StructSize;
+
+                       /*
+                        * For the VPD the instance is not an index number
+                        * but the key itself. Determin with the instance
+                        * counter the VPD key to be used.
+                        */
+                       if (IdTable[TableIndex].Id == OID_SKGE_VPD_KEY ||
+                               IdTable[TableIndex].Id == OID_SKGE_VPD_VALUE ||
+                               IdTable[TableIndex].Id == OID_SKGE_VPD_ACCESS ||
+                               IdTable[TableIndex].Id == OID_SKGE_VPD_ACTION) {
+
+                               SK_STRNCPY((char *)&Instance, KeyArr[InstanceCnt - 1], 4);
+                       }
+                       else {
+                               Instance = (SK_U32)InstanceCnt;
+                       }
+
+                       TmpLen = *pLen - DstOffset;
+                       Ret = IdTable[TableIndex].Func(pAC, IoC, SK_PNMI_GET,
+                               IdTable[TableIndex].Id, (char *)pBuf +
+                               DstOffset, &TmpLen, Instance, TableIndex, NetIndex);
+
+                       /*
+                        * An unknown instance error means that we reached
+                        * the last instance of that variable. Proceed with
+                        * the next OID in the table and ignore the return
+                        * code.
+                        */
+                       if (Ret == SK_PNMI_ERR_UNKNOWN_INST) {
+
+                break;
+                       }
+
+                       if (Ret != SK_PNMI_ERR_OK) {
+
+                               pAC->Pnmi.MacUpdatedFlag --;
+                               pAC->Pnmi.RlmtUpdatedFlag --;
+                               pAC->Pnmi.SirqUpdatedFlag --;
+
+                               SK_PNMI_CHECKFLAGS("SkPnmiGetStruct: On return");
+                               SK_PNMI_SET_STAT(pBuf, Ret, DstOffset);
+                               *pLen = SK_PNMI_MIN_STRUCT_SIZE;
+                               return (Ret);
+                       }
+               }
+       }
+
+       pAC->Pnmi.MacUpdatedFlag --;
+       pAC->Pnmi.RlmtUpdatedFlag --;
+       pAC->Pnmi.SirqUpdatedFlag --;
+
+       *pLen = SK_PNMI_STRUCT_SIZE;
+       SK_PNMI_CHECKFLAGS("SkPnmiGetStruct: On return");
+       SK_PNMI_SET_STAT(pBuf, SK_PNMI_ERR_OK, (SK_U32)(-1));
+       return (SK_PNMI_ERR_OK);
+}
+
+/*****************************************************************************
+ *
+ * SkPnmiPreSetStruct - Presets the management database in SK_PNMI_STRUCT_DATA
+ *
+ * Description:
+ *     Calls a general sub-function for all this set stuff. The preset does
+ *     the same as a set, but returns just before finally setting the
+ *     new value. This is useful to check if a set might be successfull.
+ *     The sub-function runs through the IdTable, checks which OIDs are able
+ *     to set, and calls the handler function of the OID to perform the
+ *     preset. The return value of the function will also be stored in
+ *     SK_PNMI_STRUCT_DATA if the passed buffer has the minimum size of
+ *     SK_PNMI_MIN_STRUCT_SIZE.
+ *
+ * Returns:
+ *     SK_PNMI_ERR_OK           The request was successfully performed.
+ *     SK_PNMI_ERR_GENERAL      A general severe internal error occured.
+ *     SK_PNMI_ERR_TOO_SHORT    The passed buffer is too short to contain
+ *                              the correct data (e.g. a 32bit value is
+ *                              needed, but a 16 bit value was passed).
+ *     SK_PNMI_ERR_BAD_VALUE    The passed value is not in the valid
+ *                              value range.
+ */
+int SkPnmiPreSetStruct(
+SK_AC *pAC,            /* Pointer to adapter context */
+SK_IOC IoC,            /* IO context handle */
+void *pBuf,            /* Buffer which contains the data to be set */
+unsigned int *pLen,    /* Length of buffer */
+SK_U32 NetIndex)       /* NetIndex (0..n), in single net mode always zero */
+{
+       SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_CTRL,
+               ("PNMI: SkPnmiPreSetStruct: Called, BufLen=%d, NetIndex=%d\n",
+                       *pLen, NetIndex));
+
+       return (PnmiStruct(pAC, IoC, SK_PNMI_PRESET, (char *)pBuf,
+                                       pLen, NetIndex));
+}
+
+/*****************************************************************************
+ *
+ * SkPnmiSetStruct - Sets the management database in SK_PNMI_STRUCT_DATA
+ *
+ * Description:
+ *     Calls a general sub-function for all this set stuff. The return value
+ *     of the function will also be stored in SK_PNMI_STRUCT_DATA if the
+ *     passed buffer has the minimum size of SK_PNMI_MIN_STRUCT_SIZE.
+ *     The sub-function runs through the IdTable, checks which OIDs are able
+ *     to set, and calls the handler function of the OID to perform the
+ *     set. The return value of the function will also be stored in
+ *     SK_PNMI_STRUCT_DATA if the passed buffer has the minimum size of
+ *     SK_PNMI_MIN_STRUCT_SIZE.
+ *
+ * Returns:
+ *     SK_PNMI_ERR_OK           The request was successfully performed.
+ *     SK_PNMI_ERR_GENERAL      A general severe internal error occured.
+ *     SK_PNMI_ERR_TOO_SHORT    The passed buffer is too short to contain
+ *                              the correct data (e.g. a 32bit value is
+ *                              needed, but a 16 bit value was passed).
+ *     SK_PNMI_ERR_BAD_VALUE    The passed value is not in the valid
+ *                              value range.
+ */
+int SkPnmiSetStruct(
+SK_AC *pAC,            /* Pointer to adapter context */
+SK_IOC IoC,            /* IO context handle */
+void *pBuf,            /* Buffer which contains the data to be set */
+unsigned int *pLen,    /* Length of buffer */
+SK_U32 NetIndex)       /* NetIndex (0..n), in single net mode always zero */
+{
+       SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_CTRL,
+               ("PNMI: SkPnmiSetStruct: Called, BufLen=%d, NetIndex=%d\n",
+                       *pLen, NetIndex));
+
+       return (PnmiStruct(pAC, IoC, SK_PNMI_SET, (char *)pBuf,
+                                       pLen, NetIndex));
+}
+
+/*****************************************************************************
+ *
+ * SkPnmiEvent - Event handler
+ *
+ * Description:
+ *     Handles the following events:
+ *     SK_PNMI_EVT_SIRQ_OVERFLOW     When a hardware counter overflows an
+ *                                   interrupt will be generated which is
+ *                                   first handled by SIRQ which generates a
+ *                                   this event. The event increments the
+ *                                   upper 32 bit of the 64 bit counter.
+ *     SK_PNMI_EVT_SEN_XXX           The event is generated by the I2C module
+ *                                   when a sensor reports a warning or
+ *                                   error. The event will store a trap
+ *                                   message in the trap buffer.
+ *     SK_PNMI_EVT_CHG_EST_TIMER     The timer event was initiated by this
+ *                                   module and is used to calculate the
+ *                                   port switches per hour.
+ *     SK_PNMI_EVT_CLEAR_COUNTER     The event clears all counters and
+ *                                   timestamps.
+ *     SK_PNMI_EVT_XMAC_RESET        The event is generated by the driver
+ *                                   before a hard reset of the XMAC is
+ *                                   performed. All counters will be saved
+ *                                   and added to the hardware counter
+ *                                   values after reset to grant continuous
+ *                                   counter values.
+ *     SK_PNMI_EVT_RLMT_PORT_UP      Generated by RLMT to notify that a port
+ *                                   went logically up. A trap message will
+ *                                   be stored to the trap buffer.
+ *     SK_PNMI_EVT_RLMT_PORT_DOWN    Generated by RLMT to notify that a port
+ *                                   went logically down. A trap message will
+ *                                   be stored to the trap buffer.
+ *     SK_PNMI_EVT_RLMT_SEGMENTATION Generated by RLMT to notify that two
+ *                                   spanning tree root bridges were
+ *                                   detected. A trap message will be stored
+ *                                   to the trap buffer.
+ *     SK_PNMI_EVT_RLMT_ACTIVE_DOWN  Notifies PNMI that an active port went
+ *                                   down. PNMI will not further add the
+ *                                   statistic values to the virtual port.
+ *     SK_PNMI_EVT_RLMT_ACTIVE_UP    Notifies PNMI that a port went up and
+ *                                   is now an active port. PNMI will now
+ *                                   add the statistic data of this port to
+ *                                   the virtual port.
+ *     SK_PNMI_EVT_RLMT_SET_NETS     Notifies PNMI about the net mode. The first parameter
+ *                                   contains the number of nets. 1 means single net, 2 means
+ *                                   dual net. The second parameter is -1
+ *
+ * Returns:
+ *     Always 0
+ */
+int SkPnmiEvent(
+SK_AC *pAC,            /* Pointer to adapter context */
+SK_IOC IoC,            /* IO context handle */
+SK_U32 Event,          /* Event-Id */
+SK_EVPARA Param)       /* Event dependent parameter */
+{
+       unsigned int    PhysPortIndex;
+    unsigned int       MaxNetNumber;
+       int                     CounterIndex;
+       int                     Ret;
+       SK_U16          MacStatus;
+       SK_U64          OverflowStatus;
+       SK_U64          Mask;
+       int                     MacType;
+       SK_U64          Value;
+       SK_U32          Val32;
+       SK_U16          Register;
+       SK_EVPARA       EventParam;
+       SK_U64          NewestValue;
+       SK_U64          OldestValue;
+       SK_U64          Delta;
+       SK_PNMI_ESTIMATE *pEst;
+       SK_U32          NetIndex;
+       SK_GEPORT       *pPrt;
+       SK_PNMI_VCT     *pVctBackupData;
+       SK_U32          RetCode;
+       int             i;
+       SK_U32          CableLength;
+
+
+#ifdef DEBUG
+       if (Event != SK_PNMI_EVT_XMAC_RESET) {
+
+               SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_CTRL,
+                       ("PNMI: SkPnmiEvent: Called, Event=0x%x, Param=0x%x\n",
+                       (unsigned int)Event, (unsigned int)Param.Para64));
+       }
+#endif /* DEBUG */
+       SK_PNMI_CHECKFLAGS("SkPnmiEvent: On call");
+
+       MacType = pAC->GIni.GIMacType;
+       
+       switch (Event) {
+
+       case SK_PNMI_EVT_SIRQ_OVERFLOW:
+               PhysPortIndex = (int)Param.Para32[0];
+               MacStatus = (SK_U16)Param.Para32[1];
+#ifdef DEBUG
+               if (PhysPortIndex >= SK_MAX_MACS) {
+
+                       SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_CTRL,
+                               ("PNMI: ERR: SkPnmiEvent: SK_PNMI_EVT_SIRQ_OVERFLOW parameter"
+                                " wrong, PhysPortIndex=0x%x\n",
+                               PhysPortIndex));
+                       return (0);
+               }
+#endif /* DEBUG */
+               OverflowStatus = 0;
+
+               /*
+                * Check which source caused an overflow interrupt.
+                */
+               if ((pAC->GIni.GIFunc.pFnMacOverflow(pAC, IoC, PhysPortIndex,
+                               MacStatus, &OverflowStatus) != 0) ||
+                       (OverflowStatus == 0)) {
+
+                       SK_PNMI_CHECKFLAGS("SkPnmiEvent: On return");
+                       return (0);
+               }
+
+               /*
+                * Check the overflow status register and increment
+                * the upper dword of corresponding counter.
+                */
+               for (CounterIndex = 0; CounterIndex < sizeof(Mask) * 8;
+                       CounterIndex ++) {
+
+                       Mask = (SK_U64)1 << CounterIndex;
+                       if ((OverflowStatus & Mask) == 0) {
+
+                               continue;
+                       }
+
+                       switch (StatOvrflwBit[CounterIndex][MacType]) {
+
+                       case SK_PNMI_HTX_UTILUNDER:
+                       case SK_PNMI_HTX_UTILOVER:
+                               if (MacType == SK_MAC_XMAC) {
+                                       XM_IN16(IoC, PhysPortIndex, XM_TX_CMD, &Register);
+                                       Register |= XM_TX_SAM_LINE;
+                                       XM_OUT16(IoC, PhysPortIndex, XM_TX_CMD, Register);
+                               }
+                               break;
+
+                       case SK_PNMI_HRX_UTILUNDER:
+                       case SK_PNMI_HRX_UTILOVER:
+                               if (MacType == SK_MAC_XMAC) {
+                                       XM_IN16(IoC, PhysPortIndex, XM_RX_CMD, &Register);
+                                       Register |= XM_RX_SAM_LINE;
+                                       XM_OUT16(IoC, PhysPortIndex, XM_RX_CMD, Register);
+                               }
+                               break;
+
+                       case SK_PNMI_HTX_OCTETHIGH:
+                       case SK_PNMI_HTX_OCTETLOW:
+                       case SK_PNMI_HTX_RESERVED:
+                       case SK_PNMI_HRX_OCTETHIGH:
+                       case SK_PNMI_HRX_OCTETLOW:
+                       case SK_PNMI_HRX_IRLENGTH:
+                       case SK_PNMI_HRX_RESERVED:
+                       
+                       /*
+                        * the following counters aren't be handled (id > 63)
+                        */
+                       case SK_PNMI_HTX_SYNC:
+                       case SK_PNMI_HTX_SYNC_OCTET:
+                               break;
+
+                       case SK_PNMI_HRX_LONGFRAMES:
+                               if (MacType == SK_MAC_GMAC) {
+                                       pAC->Pnmi.Port[PhysPortIndex].
+                                               CounterHigh[CounterIndex] ++;
+                               }
+                               break;
+
+                       default:
+                               pAC->Pnmi.Port[PhysPortIndex].
+                                       CounterHigh[CounterIndex] ++;
+                       }
+               }
+               break;
+
+       case SK_PNMI_EVT_SEN_WAR_LOW:
+#ifdef DEBUG
+               if ((unsigned int)Param.Para64 >= (unsigned int)pAC->I2c.MaxSens) {
+
+                       SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_CTRL,
+                               ("PNMI: ERR: SkPnmiEvent: SK_PNMI_EVT_SEN_WAR_LOW parameter wrong, SensorIndex=%d\n",
+                               (unsigned int)Param.Para64));
+                       return (0);
+               }
+#endif /* DEBUG */
+
+               /*
+                * Store a trap message in the trap buffer and generate
+                * an event for user space applications with the
+                * SK_DRIVER_SENDEVENT macro.
+                */
+               QueueSensorTrap(pAC, OID_SKGE_TRAP_SEN_WAR_LOW,
+                       (unsigned int)Param.Para64);
+               (void)SK_DRIVER_SENDEVENT(pAC, IoC);
+               break;
+
+       case SK_PNMI_EVT_SEN_WAR_UPP:
+#ifdef DEBUG
+               if ((unsigned int)Param.Para64 >= (unsigned int)pAC->I2c.MaxSens) {
+
+                       SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_CTRL,
+                               ("PNMI: ERR: SkPnmiEvent: SK_PNMI_EVT_SEN_WAR_UPP parameter wrong, SensorIndex=%d\n",
+                               (unsigned int)Param.Para64));
+                       return (0);
+               }
+#endif /* DEBUG */
+
+               /*
+                * Store a trap message in the trap buffer and generate
+                * an event for user space applications with the
+                * SK_DRIVER_SENDEVENT macro.
+                */
+               QueueSensorTrap(pAC, OID_SKGE_TRAP_SEN_WAR_UPP,
+                       (unsigned int)Param.Para64);
+               (void)SK_DRIVER_SENDEVENT(pAC, IoC);
+               break;
+
+       case SK_PNMI_EVT_SEN_ERR_LOW:
+#ifdef DEBUG
+               if ((unsigned int)Param.Para64 >= (unsigned int)pAC->I2c.MaxSens) {
+
+                       SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_CTRL,
+                               ("PNMI: ERR: SkPnmiEvent: SK_PNMI_EVT_SEN_ERR_LOW parameter wrong, SensorIndex=%d\n",
+                               (unsigned int)Param.Para64));
+                       return (0);
+               }
+#endif /* DEBUG */
+
+               /*
+                * Store a trap message in the trap buffer and generate
+                * an event for user space applications with the
+                * SK_DRIVER_SENDEVENT macro.
+                */
+               QueueSensorTrap(pAC, OID_SKGE_TRAP_SEN_ERR_LOW,
+                       (unsigned int)Param.Para64);
+               (void)SK_DRIVER_SENDEVENT(pAC, IoC);
+               break;
+       
+       case SK_PNMI_EVT_SEN_ERR_UPP:
+#ifdef DEBUG
+               if ((unsigned int)Param.Para64 >= (unsigned int)pAC->I2c.MaxSens) {
+
+                       SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_CTRL,
+                               ("PNMI: ERR: SkPnmiEvent: SK_PNMI_EVT_SEN_ERR_UPP parameter wrong, SensorIndex=%d\n",
+                               (unsigned int)Param.Para64));
+                       return (0);
+               }
+#endif /* DEBUG */
+
+               /*
+                * Store a trap message in the trap buffer and generate
+                * an event for user space applications with the
+                * SK_DRIVER_SENDEVENT macro.
+                */
+               QueueSensorTrap(pAC, OID_SKGE_TRAP_SEN_ERR_UPP,
+                       (unsigned int)Param.Para64);
+               (void)SK_DRIVER_SENDEVENT(pAC, IoC);
+               break;
+
+       case SK_PNMI_EVT_CHG_EST_TIMER:
+               /*
+                * Calculate port switch average on a per hour basis
+                *   Time interval for check       : 28125 ms
+                *   Number of values for average  : 8
+                *
+                * Be careful in changing these values, on change check
+                *   - typedef of SK_PNMI_ESTIMATE (Size of EstValue
+                *     array one less than value number)
+                *   - Timer initialization SkTimerStart() in SkPnmiInit
+                *   - Delta value below must be multiplicated with
+                *     power of 2
+                *
+                */
+               pEst = &pAC->Pnmi.RlmtChangeEstimate;
+               CounterIndex = pEst->EstValueIndex + 1;
+               if (CounterIndex == 7) {
+
+                       CounterIndex = 0;
+               }
+               pEst->EstValueIndex = CounterIndex;
+
+               NewestValue = pAC->Pnmi.RlmtChangeCts;
+               OldestValue = pEst->EstValue[CounterIndex];
+               pEst->EstValue[CounterIndex] = NewestValue;
+
+               /*
+                * Calculate average. Delta stores the number of
+                * port switches per 28125 * 8 = 225000 ms
+                */
+               if (NewestValue >= OldestValue) {
+
+                       Delta = NewestValue - OldestValue;
+               }
+               else {
+                       /* Overflow situation */
+                       Delta = (SK_U64)(0 - OldestValue) + NewestValue;
+               }
+
+               /*
+                * Extrapolate delta to port switches per hour.
+                *     Estimate = Delta * (3600000 / 225000)
+                *              = Delta * 16
+                *              = Delta << 4
+                */
+               pAC->Pnmi.RlmtChangeEstimate.Estimate = Delta << 4;
+
+               /*
+                * Check if threshold is exceeded. If the threshold is
+                * permanently exceeded every 28125 ms an event will be
+                * generated to remind the user of this condition.
+                */
+               if ((pAC->Pnmi.RlmtChangeThreshold != 0) &&
+                       (pAC->Pnmi.RlmtChangeEstimate.Estimate >=
+                       pAC->Pnmi.RlmtChangeThreshold)) {
+
+                       QueueSimpleTrap(pAC, OID_SKGE_TRAP_RLMT_CHANGE_THRES);
+                       (void)SK_DRIVER_SENDEVENT(pAC, IoC);
+               }
+
+               SK_MEMSET((char *)&EventParam, 0, sizeof(EventParam));
+               SkTimerStart(pAC, IoC, &pAC->Pnmi.RlmtChangeEstimate.EstTimer,
+                       28125000, SKGE_PNMI, SK_PNMI_EVT_CHG_EST_TIMER,
+                       EventParam);
+               break;
+
+       case SK_PNMI_EVT_CLEAR_COUNTER:
+               /*
+                *  Param.Para32[0] contains the NetIndex (0 ..1).
+                *  Param.Para32[1] is reserved, contains -1.
+                */
+               NetIndex = (SK_U32)Param.Para32[0];
+
+#ifdef DEBUG
+               if (NetIndex >= pAC->Rlmt.NumNets) {
+
+                       SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_CTRL,
+                               ("PNMI: ERR: SkPnmiEvent: SK_PNMI_EVT_CLEAR_COUNTER parameter wrong, NetIndex=%d\n",
+                               NetIndex));
+
+                       return (0);
+               }
+#endif /* DEBUG */
+
+               /*
+                * Set all counters and timestamps to zero.
+                * The according NetIndex is required as a
+                * parameter of the event.
+                */
+               ResetCounter(pAC, IoC, NetIndex);
+               break;
+
+       case SK_PNMI_EVT_XMAC_RESET:
+               /*
+                * To grant continuous counter values store the current
+                * XMAC statistic values to the entries 1..n of the
+                * CounterOffset array. XMAC Errata #2
+                */
+#ifdef DEBUG
+               if ((unsigned int)Param.Para64 >= SK_MAX_MACS) {
+
+                       SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_CTRL,
+                               ("PNMI: ERR: SkPnmiEvent: SK_PNMI_EVT_XMAC_RESET parameter wrong, PhysPortIndex=%d\n",
+                               (unsigned int)Param.Para64));
+                       return (0);
+               }
+#endif
+               PhysPortIndex = (unsigned int)Param.Para64;
+
+               /*
+                * Update XMAC statistic to get fresh values
+                */
+               Ret = MacUpdate(pAC, IoC, 0, pAC->GIni.GIMacsFound - 1);
+               if (Ret != SK_PNMI_ERR_OK) {
+
+                       SK_PNMI_CHECKFLAGS("SkPnmiEvent: On return");
+                       return (0);
+               }
+               /*
+                * Increment semaphore to indicate that an update was
+                * already done
+                */
+               pAC->Pnmi.MacUpdatedFlag ++;
+
+               for (CounterIndex = 0; CounterIndex < SK_PNMI_MAX_IDX;
+                       CounterIndex ++) {
+
+                       if (!StatAddr[CounterIndex][MacType].GetOffset) {
+
+                               continue;
+                       }
+
+                       pAC->Pnmi.Port[PhysPortIndex].CounterOffset[CounterIndex] =
+                               GetPhysStatVal(pAC, IoC, PhysPortIndex, CounterIndex);
+                       
+                       pAC->Pnmi.Port[PhysPortIndex].CounterHigh[CounterIndex] = 0;
+               }
+
+               pAC->Pnmi.MacUpdatedFlag --;
+               break;
+
+       case SK_PNMI_EVT_RLMT_PORT_UP:
+               PhysPortIndex = (unsigned int)Param.Para32[0];
+#ifdef DEBUG
+               if (PhysPortIndex >= SK_MAX_MACS) {
+
+                       SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_CTRL,
+                               ("PNMI: ERR: SkPnmiEvent: SK_PNMI_EVT_RLMT_PORT_UP parameter"
+                 " wrong, PhysPortIndex=%d\n", PhysPortIndex));
+
+                       return (0);
+               }
+#endif /* DEBUG */
+
+               /*
+                * Store a trap message in the trap buffer and generate an event for
+                * user space applications with the SK_DRIVER_SENDEVENT macro.
+                */
+               QueueRlmtPortTrap(pAC, OID_SKGE_TRAP_RLMT_PORT_UP, PhysPortIndex);
+               (void)SK_DRIVER_SENDEVENT(pAC, IoC);
+
+               /* Bugfix for XMAC errata (#10620)*/
+               if (MacType == SK_MAC_XMAC) {
+                       /* Add incremental difference to offset (#10620)*/
+                       (void)pAC->GIni.GIFunc.pFnMacStatistic(pAC, IoC, PhysPortIndex,
+                               XM_RXE_SHT_ERR, &Val32);
+                       
+                       Value = (((SK_U64)pAC->Pnmi.Port[PhysPortIndex].
+                                CounterHigh[SK_PNMI_HRX_SHORTS] << 32) | (SK_U64)Val32);
+                       pAC->Pnmi.Port[PhysPortIndex].CounterOffset[SK_PNMI_HRX_SHORTS] +=
+                               Value - pAC->Pnmi.Port[PhysPortIndex].RxShortZeroMark;
+               }
+               
+               /* Tell VctStatus() that a link was up meanwhile. */
+               pAC->Pnmi.VctStatus[PhysPortIndex] |= SK_PNMI_VCT_LINK;         
+               break;
+
+    case SK_PNMI_EVT_RLMT_PORT_DOWN:
+               PhysPortIndex = (unsigned int)Param.Para32[0];
+
+#ifdef DEBUG
+               if (PhysPortIndex >= SK_MAX_MACS) {
+
+                       SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_CTRL,
+                               ("PNMI: ERR: SkPnmiEvent: SK_PNMI_EVT_RLMT_PORT_DOWN parameter"
+                 " wrong, PhysPortIndex=%d\n", PhysPortIndex));
+
+                       return (0);
+               }
+#endif /* DEBUG */
+
+               /*
+                * Store a trap message in the trap buffer and generate an event for
+                * user space applications with the SK_DRIVER_SENDEVENT macro.
+                */
+               QueueRlmtPortTrap(pAC, OID_SKGE_TRAP_RLMT_PORT_DOWN, PhysPortIndex);
+               (void)SK_DRIVER_SENDEVENT(pAC, IoC);
+
+               /* Bugfix #10620 - get zero level for incremental difference */
+               if (MacType == SK_MAC_XMAC) {
+
+                       (void)pAC->GIni.GIFunc.pFnMacStatistic(pAC, IoC, PhysPortIndex,
+                               XM_RXE_SHT_ERR, &Val32);
+                       
+                       pAC->Pnmi.Port[PhysPortIndex].RxShortZeroMark =
+                               (((SK_U64)pAC->Pnmi.Port[PhysPortIndex].
+                                CounterHigh[SK_PNMI_HRX_SHORTS] << 32) | (SK_U64)Val32);
+               }
+               break;
+
+       case SK_PNMI_EVT_RLMT_ACTIVE_DOWN:
+               PhysPortIndex = (unsigned int)Param.Para32[0];
+               NetIndex = (SK_U32)Param.Para32[1];
+
+#ifdef DEBUG
+               if (PhysPortIndex >= SK_MAX_MACS) {
+
+                       SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_CTRL,
+                               ("PNMI: ERR: SkPnmiEvent: SK_PNMI_EVT_RLMT_ACTIVE_DOWN parameter too high, PhysPort=%d\n",
+                               PhysPortIndex));
+               }
+
+               if (NetIndex >= pAC->Rlmt.NumNets) {
+
+                       SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_CTRL,
+                               ("PNMI: ERR: SkPnmiEvent: SK_PNMI_EVT_RLMT_ACTIVE_DOWN parameter too high, NetIndex=%d\n",
+                               NetIndex));
+               }
+#endif /* DEBUG */
+
+               /*
+                * For now, ignore event if NetIndex != 0.
+                */
+               if (Param.Para32[1] != 0) {
+
+                       return (0);
+               }
+
+               /*
+                * Nothing to do if port is already inactive
+                */
+               if (!pAC->Pnmi.Port[PhysPortIndex].ActiveFlag) {
+
+                       return (0);
+               }
+
+               /*
+                * Update statistic counters to calculate new offset for the virtual
+                * port and increment semaphore to indicate that an update was already
+                * done.
+                */
+               if (MacUpdate(pAC, IoC, 0, pAC->GIni.GIMacsFound - 1) !=
+                       SK_PNMI_ERR_OK) {
+
+                       SK_PNMI_CHECKFLAGS("SkPnmiEvent: On return");
+                       return (0);
+               }
+               pAC->Pnmi.MacUpdatedFlag ++;
+
+               /*
+                * Calculate new counter offset for virtual port to grant continous
+                * counting on port switches. The virtual port consists of all currently
+                * active ports. The port down event indicates that a port is removed
+                * from the virtual port. Therefore add the counter value of the removed
+                * port to the CounterOffset for the virtual port to grant the same
+                * counter value.
+                */
+               for (CounterIndex = 0; CounterIndex < SK_PNMI_MAX_IDX;
+                       CounterIndex ++) {
+
+                       if (!StatAddr[CounterIndex][MacType].GetOffset) {
+
+                               continue;
+                       }
+
+                       Value = GetPhysStatVal(pAC, IoC, PhysPortIndex, CounterIndex);
+
+                       pAC->Pnmi.VirtualCounterOffset[CounterIndex] += Value;
+               }
+
+               /*
+                * Set port to inactive
+                */
+               pAC->Pnmi.Port[PhysPortIndex].ActiveFlag = SK_FALSE;
+
+               pAC->Pnmi.MacUpdatedFlag --;
+               break;
+
+       case SK_PNMI_EVT_RLMT_ACTIVE_UP:
+               PhysPortIndex = (unsigned int)Param.Para32[0];
+               NetIndex = (SK_U32)Param.Para32[1];
+
+#ifdef DEBUG
+               if (PhysPortIndex >= SK_MAX_MACS) {
+
+                       SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_CTRL,
+                               ("PNMI: ERR: SkPnmiEvent: SK_PNMI_EVT_RLMT_ACTIVE_UP parameter too high, PhysPort=%d\n",
+                               PhysPortIndex));
+               }
+
+               if (NetIndex >= pAC->Rlmt.NumNets) {
+
+                       SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_CTRL,
+                               ("PNMI: ERR: SkPnmiEvent: SK_PNMI_EVT_RLMT_ACTIVE_UP parameter too high, NetIndex=%d\n",
+                               NetIndex));
+               }
+#endif /* DEBUG */
+
+               /*
+                * For now, ignore event if NetIndex != 0.
+                */
+               if (Param.Para32[1] != 0) {
+
+                       return (0);
+               }
+
+               /*
+                * Nothing to do if port is already active
+                */
+               if (pAC->Pnmi.Port[PhysPortIndex].ActiveFlag) {
+
+                       return (0);
+               }
+
+               /*
+                * Statistic maintenance
+                */
+               pAC->Pnmi.RlmtChangeCts ++;
+               pAC->Pnmi.RlmtChangeTime = SK_PNMI_HUNDREDS_SEC(SkOsGetTime(pAC));
+
+               /*
+                * Store a trap message in the trap buffer and generate an event for
+                * user space applications with the SK_DRIVER_SENDEVENT macro.
+                */
+               QueueRlmtNewMacTrap(pAC, PhysPortIndex);
+               (void)SK_DRIVER_SENDEVENT(pAC, IoC);
+
+               /*
+                * Update statistic counters to calculate new offset for the virtual
+                * port and increment semaphore to indicate that an update was
+                * already done.
+                */
+               if (MacUpdate(pAC, IoC, 0, pAC->GIni.GIMacsFound - 1) !=
+                       SK_PNMI_ERR_OK) {
+
+                       SK_PNMI_CHECKFLAGS("SkPnmiEvent: On return");
+                       return (0);
+               }
+               pAC->Pnmi.MacUpdatedFlag ++;
+
+               /*
+                * Calculate new counter offset for virtual port to grant continous
+                * counting on port switches. A new port is added to the virtual port.
+                * Therefore substract the counter value of the new port from the
+                * CounterOffset for the virtual port to grant the same value.
+                */
+               for (CounterIndex = 0; CounterIndex < SK_PNMI_MAX_IDX;
+                       CounterIndex ++) {
+
+                       if (!StatAddr[CounterIndex][MacType].GetOffset) {
+
+                               continue;
+                       }
+
+                       Value = GetPhysStatVal(pAC, IoC, PhysPortIndex, CounterIndex);
+
+                       pAC->Pnmi.VirtualCounterOffset[CounterIndex] -= Value;
+               }
+
+               /* Set port to active */
+               pAC->Pnmi.Port[PhysPortIndex].ActiveFlag = SK_TRUE;
+
+               pAC->Pnmi.MacUpdatedFlag --;
+               break;
+
+       case SK_PNMI_EVT_RLMT_SEGMENTATION:
+               /*
+                * Para.Para32[0] contains the NetIndex.
+                */
+
+               /*
+                * Store a trap message in the trap buffer and generate an event for
+                * user space applications with the SK_DRIVER_SENDEVENT macro.
+                */
+               QueueSimpleTrap(pAC, OID_SKGE_TRAP_RLMT_SEGMENTATION);
+               (void)SK_DRIVER_SENDEVENT(pAC, IoC);
+               break;
+
+    case SK_PNMI_EVT_RLMT_SET_NETS:
+               /*
+                *  Param.Para32[0] contains the number of Nets.
+                *  Param.Para32[1] is reserved, contains -1.
+                */
+           /*
+        * Check number of nets
+                */
+               MaxNetNumber = pAC->GIni.GIMacsFound;
+               if (((unsigned int)Param.Para32[0] < 1)
+                       || ((unsigned int)Param.Para32[0] > MaxNetNumber)) {
+                       return (SK_PNMI_ERR_UNKNOWN_NET);
+               }
+
+        if ((unsigned int)Param.Para32[0] == 1) { /* single net mode */
+               pAC->Pnmi.DualNetActiveFlag = SK_FALSE;
+        }
+        else { /* dual net mode */
+               pAC->Pnmi.DualNetActiveFlag = SK_TRUE;
+        }
+        break;
+
+    case SK_PNMI_EVT_VCT_RESET:
+               PhysPortIndex = Param.Para32[0];
+               pPrt = &pAC->GIni.GP[PhysPortIndex];
+               pVctBackupData = &pAC->Pnmi.VctBackup[PhysPortIndex];
+               
+               if (pAC->Pnmi.VctStatus[PhysPortIndex] & SK_PNMI_VCT_PENDING) {
+                       RetCode = SkGmCableDiagStatus(pAC, IoC, PhysPortIndex, SK_FALSE);
+                       if (RetCode == 2) {
+                               /*
+                                * VCT test is still running.
+                                * Start VCT timer counter again.
+                                */
+                               SK_MEMSET((char *) &Param, 0, sizeof(Param));
+                               Param.Para32[0] = PhysPortIndex;
+                               Param.Para32[1] = -1;
+                               SkTimerStart(pAC, IoC,
+                                       &pAC->Pnmi.VctTimeout[PhysPortIndex].VctTimer,
+                               4000000, SKGE_PNMI, SK_PNMI_EVT_VCT_RESET, Param);
+                               break;
+                       }
+                       pAC->Pnmi.VctStatus[PhysPortIndex] &= ~SK_PNMI_VCT_PENDING;
+                       pAC->Pnmi.VctStatus[PhysPortIndex] |=
+                               (SK_PNMI_VCT_NEW_VCT_DATA | SK_PNMI_VCT_TEST_DONE);
+                       
+                       /* Copy results for later use to PNMI struct. */
+                       for (i = 0; i < 4; i++)  {
+                               if (pPrt->PMdiPairSts[i] == SK_PNMI_VCT_NORMAL_CABLE) {
+                                       if ((pPrt->PMdiPairLen[i] > 35) &&
+                                               (pPrt->PMdiPairLen[i] < 0xff)) {
+                                               pPrt->PMdiPairSts[i] = SK_PNMI_VCT_IMPEDANCE_MISMATCH;
+                                       }
+                               }
+                               if ((pPrt->PMdiPairLen[i] > 35) &&
+                                       (pPrt->PMdiPairLen[i] != 0xff)) {
+                                       CableLength = 1000 *
+                                               (((175 * pPrt->PMdiPairLen[i]) / 210) - 28);
+                               }
+                               else {
+                                       CableLength = 0;
+                               }
+                               pVctBackupData->PMdiPairLen[i] = CableLength;
+                               pVctBackupData->PMdiPairSts[i] = pPrt->PMdiPairSts[i];
+                       }
+                       
+                       Param.Para32[0] = PhysPortIndex;
+                       Param.Para32[1] = -1;
+                       SkEventQueue(pAC, SKGE_DRV, SK_DRV_PORT_RESET, Param);
+                       SkEventDispatcher(pAC, IoC);
+               }
+               
+               break;
+
+       default:
+               break;
+       }
+
+       SK_PNMI_CHECKFLAGS("SkPnmiEvent: On return");
+       return (0);
+}
+
+
+/******************************************************************************
+ *
+ * Private functions
+ *
+ */
+
+/*****************************************************************************
+ *
+ * PnmiVar - Gets, presets, and sets single OIDs
+ *
+ * Description:
+ *     Looks up the requested OID, calls the corresponding handler
+ *     function, and passes the parameters with the get, preset, or
+ *     set command. The function is called by SkGePnmiGetVar,
+ *     SkGePnmiPreSetVar, or SkGePnmiSetVar.
+ *
+ * Returns:
+ *     SK_PNMI_ERR_XXX. For details have a look at the description of the
+ *     calling functions.
+ *     SK_PNMI_ERR_UNKNOWN_NET  The requested NetIndex doesn't exist
+ */
+PNMI_STATIC int PnmiVar(
+SK_AC *pAC,            /* Pointer to adapter context */
+SK_IOC IoC,            /* IO context handle */
+int Action,            /* GET/PRESET/SET action */
+SK_U32 Id,             /* Object ID that is to be processed */
+char *pBuf,            /* Buffer used for the management data transfer */
+unsigned int *pLen,    /* Total length of pBuf management data  */
+SK_U32 Instance,       /* Instance (1..n) that is to be set or -1 */
+SK_U32 NetIndex)       /* NetIndex (0..n), in single net mode always zero */
+{
+       unsigned int    TableIndex;
+       int             Ret;
+
+
+       if ((TableIndex = LookupId(Id)) == (unsigned int)(-1)) {
+
+               *pLen = 0;
+               return (SK_PNMI_ERR_UNKNOWN_OID);
+       }
+       
+    /* Check NetIndex */
+       if (NetIndex >= pAC->Rlmt.NumNets) {
+               return (SK_PNMI_ERR_UNKNOWN_NET);
+       }
+
+       SK_PNMI_CHECKFLAGS("PnmiVar: On call");
+
+       Ret = IdTable[TableIndex].Func(pAC, IoC, Action, Id, pBuf, pLen,
+               Instance, TableIndex, NetIndex);
+
+       SK_PNMI_CHECKFLAGS("PnmiVar: On return");
+
+       return (Ret);
+}
+
+/*****************************************************************************
+ *
+ * PnmiStruct - Presets and Sets data in structure SK_PNMI_STRUCT_DATA
+ *
+ * Description:
+ *     The return value of the function will also be stored in
+ *     SK_PNMI_STRUCT_DATA if the passed buffer has the minimum size of
+ *     SK_PNMI_MIN_STRUCT_SIZE. The sub-function runs through the IdTable,
+ *     checks which OIDs are able to set, and calls the handler function of
+ *     the OID to perform the set. The return value of the function will
+ *     also be stored in SK_PNMI_STRUCT_DATA if the passed buffer has the
+ *     minimum size of SK_PNMI_MIN_STRUCT_SIZE. The function is called
+ *     by SkGePnmiPreSetStruct and SkGePnmiSetStruct.
+ *
+ * Returns:
+ *     SK_PNMI_ERR_XXX. The codes are described in the calling functions.
+ *     SK_PNMI_ERR_UNKNOWN_NET  The requested NetIndex doesn't exist
+ */
+PNMI_STATIC int PnmiStruct(
+SK_AC *pAC,            /* Pointer to adapter context */
+SK_IOC IoC,            /* IO context handle */
+int  Action,   /* PRESET/SET action to be performed */
+char *pBuf,            /* Buffer used for the management data transfer */
+unsigned int *pLen,    /* Length of pBuf management data buffer */
+SK_U32 NetIndex)       /* NetIndex (0..n), in single net mode always zero */
+{
+       int             Ret;
+       unsigned int    TableIndex;
+       unsigned int    DstOffset;
+       unsigned int    Len;
+       unsigned int    InstanceNo;
+       unsigned int    InstanceCnt;
+       SK_U32          Instance;
+       SK_U32          Id;
+
+
+       /* Check if the passed buffer has the right size */
+       if (*pLen < SK_PNMI_STRUCT_SIZE) {
+
+               /* Check if we can return the error within the buffer */
+               if (*pLen >= SK_PNMI_MIN_STRUCT_SIZE) {
+
+                       SK_PNMI_SET_STAT(pBuf, SK_PNMI_ERR_TOO_SHORT,
+                               (SK_U32)(-1));
+               }
+
+               *pLen = SK_PNMI_STRUCT_SIZE;
+               return (SK_PNMI_ERR_TOO_SHORT);
+       }
+       
+    /* Check NetIndex */
+       if (NetIndex >= pAC->Rlmt.NumNets) {
+               return (SK_PNMI_ERR_UNKNOWN_NET);
+       }
+       
+       SK_PNMI_CHECKFLAGS("PnmiStruct: On call");
+
+       /*
+        * Update the values of RLMT and SIRQ and increment semaphores to
+        * indicate that an update was already done.
+        */
+       if ((Ret = RlmtUpdate(pAC, IoC, NetIndex)) != SK_PNMI_ERR_OK) {
+
+               SK_PNMI_SET_STAT(pBuf, Ret, (SK_U32)(-1));
+               *pLen = SK_PNMI_MIN_STRUCT_SIZE;
+               return (Ret);
+       }
+
+       if ((Ret = SirqUpdate(pAC, IoC)) != SK_PNMI_ERR_OK) {
+
+               SK_PNMI_SET_STAT(pBuf, Ret, (SK_U32)(-1));
+               *pLen = SK_PNMI_MIN_STRUCT_SIZE;
+               return (Ret);
+       }
+
+       pAC->Pnmi.RlmtUpdatedFlag ++;
+       pAC->Pnmi.SirqUpdatedFlag ++;
+
+       /* Preset/Set values */
+       for (TableIndex = 0; TableIndex < ID_TABLE_SIZE; TableIndex ++) {
+
+               if ((IdTable[TableIndex].Access != SK_PNMI_RW) &&
+                       (IdTable[TableIndex].Access != SK_PNMI_WO)) {
+
+                       continue;
+               }
+
+               InstanceNo = IdTable[TableIndex].InstanceNo;
+               Id = IdTable[TableIndex].Id;
+
+               for (InstanceCnt = 1; InstanceCnt <= InstanceNo;
+                       InstanceCnt ++) {
+
+                       DstOffset = IdTable[TableIndex].Offset +
+                               (InstanceCnt - 1) *
+                               IdTable[TableIndex].StructSize;
+
+                       /*
+                        * Because VPD multiple instance variables are
+                        * not setable we do not need to evaluate VPD
+                        * instances. Have a look to VPD instance
+                        * calculation in SkPnmiGetStruct().
+                        */
+                       Instance = (SK_U32)InstanceCnt;
+
+                       /*
+                        * Evaluate needed buffer length
+                        */
+                       Len = 0;
+                       Ret = IdTable[TableIndex].Func(pAC, IoC,
+                               SK_PNMI_GET, IdTable[TableIndex].Id,
+                               NULL, &Len, Instance, TableIndex, NetIndex);
+
+                       if (Ret == SK_PNMI_ERR_UNKNOWN_INST) {
+
+                               break;
+                       }
+                       if (Ret != SK_PNMI_ERR_TOO_SHORT) {
+
+                               pAC->Pnmi.RlmtUpdatedFlag --;
+                               pAC->Pnmi.SirqUpdatedFlag --;
+
+                               SK_PNMI_CHECKFLAGS("PnmiStruct: On return");
+                               SK_PNMI_SET_STAT(pBuf,
+                                       SK_PNMI_ERR_GENERAL, DstOffset);
+                               *pLen = SK_PNMI_MIN_STRUCT_SIZE;
+                               return (SK_PNMI_ERR_GENERAL);
+                       }
+                       if (Id == OID_SKGE_VPD_ACTION) {
+
+                               switch (*(pBuf + DstOffset)) {
+
+                               case SK_PNMI_VPD_CREATE:
+                                       Len = 3 + *(pBuf + DstOffset + 3);
+                                       break;
+
+                               case SK_PNMI_VPD_DELETE:
+                                       Len = 3;
+                                       break;
+
+                               default:
+                                       Len = 1;
+                                       break;
+                               }
+                       }
+
+                       /* Call the OID handler function */
+                       Ret = IdTable[TableIndex].Func(pAC, IoC, Action,
+                               IdTable[TableIndex].Id, pBuf + DstOffset,
+                               &Len, Instance, TableIndex, NetIndex);
+
+                       if (Ret != SK_PNMI_ERR_OK) {
+
+                               pAC->Pnmi.RlmtUpdatedFlag --;
+                               pAC->Pnmi.SirqUpdatedFlag --;
+
+                               SK_PNMI_CHECKFLAGS("PnmiStruct: On return");
+                               SK_PNMI_SET_STAT(pBuf, SK_PNMI_ERR_BAD_VALUE,
+                                       DstOffset);
+                               *pLen = SK_PNMI_MIN_STRUCT_SIZE;
+                               return (SK_PNMI_ERR_BAD_VALUE);
+                       }
+               }
+       }
+
+       pAC->Pnmi.RlmtUpdatedFlag --;
+       pAC->Pnmi.SirqUpdatedFlag --;
+
+       SK_PNMI_CHECKFLAGS("PnmiStruct: On return");
+       SK_PNMI_SET_STAT(pBuf, SK_PNMI_ERR_OK, (SK_U32)(-1));
+       return (SK_PNMI_ERR_OK);
+}
+
+/*****************************************************************************
+ *
+ * LookupId - Lookup an OID in the IdTable
+ *
+ * Description:
+ *     Scans the IdTable to find the table entry of an OID.
+ *
+ * Returns:
+ *     The table index or -1 if not found.
+ */
+PNMI_STATIC int LookupId(
+SK_U32 Id)             /* Object identifier to be searched */
+{
+       int i;
+
+       for (i = 0; i < ID_TABLE_SIZE; i++) {
+
+               if (IdTable[i].Id == Id) {
+
+                       return i;
+               }
+       }
+
+       return (-1);
+}
+
+/*****************************************************************************
+ *
+ * OidStruct - Handler of OID_SKGE_ALL_DATA
+ *
+ * Description:
+ *     This OID performs a Get/Preset/SetStruct call and returns all data
+ *     in a SK_PNMI_STRUCT_DATA structure.
+ *
+ * Returns:
+ *     SK_PNMI_ERR_OK           The request was successfully performed.
+ *     SK_PNMI_ERR_GENERAL      A general severe internal error occured.
+ *     SK_PNMI_ERR_TOO_SHORT    The passed buffer is too short to contain
+ *                              the correct data (e.g. a 32bit value is
+ *                              needed, but a 16 bit value was passed).
+ *     SK_PNMI_ERR_BAD_VALUE    The passed value is not in the valid
+ *                              value range.
+ *     SK_PNMI_ERR_READ_ONLY    The OID is read-only and cannot be set.
+ *     SK_PNMI_ERR_UNKNOWN_INST The requested instance of the OID doesn't
+ *                           exist (e.g. port instance 3 on a two port
+ *                              adapter.
+ */
+PNMI_STATIC int OidStruct(
+SK_AC *pAC,            /* Pointer to adapter context */
+SK_IOC IoC,            /* IO context handle */
+int Action,            /* GET/PRESET/SET action */
+SK_U32 Id,             /* Object ID that is to be processed */
+char *pBuf,            /* Buffer used for the management data transfer */
+unsigned int *pLen,    /* On call: pBuf buffer length. On return: used buffer */
+SK_U32 Instance,       /* Instance (1..n) that is to be queried or -1 */
+unsigned int TableIndex, /* Index to the Id table */
+SK_U32 NetIndex)       /* NetIndex (0..n), in single net mode always zero */
+{
+       if (Id != OID_SKGE_ALL_DATA) {
+
+               SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR003,
+                       SK_PNMI_ERR003MSG);
+
+               *pLen = 0;
+               return (SK_PNMI_ERR_GENERAL);
+       }
+
+       /*
+        * Check instance. We only handle single instance variables
+        */
+       if (Instance != (SK_U32)(-1) && Instance != 1) {
+
+               *pLen = 0;
+               return (SK_PNMI_ERR_UNKNOWN_INST);
+       }
+
+       switch (Action) {
+
+       case SK_PNMI_GET:
+               return (SkPnmiGetStruct(pAC, IoC, pBuf, pLen, NetIndex));
+
+       case SK_PNMI_PRESET:
+               return (SkPnmiPreSetStruct(pAC, IoC, pBuf, pLen, NetIndex));
+
+       case SK_PNMI_SET:
+               return (SkPnmiSetStruct(pAC, IoC, pBuf, pLen, NetIndex));
+       }
+
+       SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR004, SK_PNMI_ERR004MSG);
+
+       *pLen = 0;
+       return (SK_PNMI_ERR_GENERAL);
+}
+
+/*****************************************************************************
+ *
+ * Perform - OID handler of OID_SKGE_ACTION
+ *
+ * Description:
+ *     None.
+ *
+ * Returns:
+ *     SK_PNMI_ERR_OK           The request was successfully performed.
+ *     SK_PNMI_ERR_GENERAL      A general severe internal error occured.
+ *     SK_PNMI_ERR_TOO_SHORT    The passed buffer is too short to contain
+ *                              the correct data (e.g. a 32bit value is
+ *                              needed, but a 16 bit value was passed).
+ *     SK_PNMI_ERR_BAD_VALUE    The passed value is not in the valid
+ *                              value range.
+ *     SK_PNMI_ERR_READ_ONLY    The OID is read-only and cannot be set.
+ *     SK_PNMI_ERR_UNKNOWN_INST The requested instance of the OID doesn't
+ *                           exist (e.g. port instance 3 on a two port
+ *                              adapter.
+ */
+PNMI_STATIC int Perform(
+SK_AC *pAC,            /* Pointer to adapter context */
+SK_IOC IoC,            /* IO context handle */
+int Action,            /* GET/PRESET/SET action */
+SK_U32 Id,             /* Object ID that is to be processed */
+char *pBuf,            /* Buffer used for the management data transfer */
+unsigned int *pLen,    /* On call: pBuf buffer length. On return: used buffer */
+SK_U32 Instance,       /* Instance (1..n) that is to be queried or -1 */
+unsigned int TableIndex, /* Index to the Id table */
+SK_U32 NetIndex)       /* NetIndex (0..n), in single net mode always zero */
+{
+       int     Ret;
+       SK_U32  ActionOp;
+
+
+       /*
+        * Check instance. We only handle single instance variables
+        */
+       if (Instance != (SK_U32)(-1) && Instance != 1) {
+
+               *pLen = 0;
+               return (SK_PNMI_ERR_UNKNOWN_INST);
+       }
+
+       if (*pLen < sizeof(SK_U32)) {
+
+               *pLen = sizeof(SK_U32);
+               return (SK_PNMI_ERR_TOO_SHORT);
+       }
+
+       /* Check if a get should be performed */
+       if (Action == SK_PNMI_GET) {
+
+               /* A get is easy. We always return the same value */
+               ActionOp = (SK_U32)SK_PNMI_ACT_IDLE;
+               SK_PNMI_STORE_U32(pBuf, ActionOp);
+               *pLen = sizeof(SK_U32);
+
+               return (SK_PNMI_ERR_OK);
+       }
+
+       /* Continue with PRESET/SET action */
+       if (*pLen > sizeof(SK_U32)) {
+
+               return (SK_PNMI_ERR_BAD_VALUE);
+       }
+
+       /* Check if the command is a known one */
+       SK_PNMI_READ_U32(pBuf, ActionOp);
+       if (*pLen > sizeof(SK_U32) ||
+               (ActionOp != SK_PNMI_ACT_IDLE &&
+               ActionOp != SK_PNMI_ACT_RESET &&
+               ActionOp != SK_PNMI_ACT_SELFTEST &&
+               ActionOp != SK_PNMI_ACT_RESETCNT)) {
+
+               *pLen = 0;
+               return (SK_PNMI_ERR_BAD_VALUE);
+       }
+
+       /* A preset ends here */
+       if (Action == SK_PNMI_PRESET) {
+
+               return (SK_PNMI_ERR_OK);
+       }
+
+       switch (ActionOp) {
+
+       case SK_PNMI_ACT_IDLE:
+               /* Nothing to do */
+               break;
+
+       case SK_PNMI_ACT_RESET:
+               /*
+                * Perform a driver reset or something that comes near
+                * to this.
+                */
+               Ret = SK_DRIVER_RESET(pAC, IoC);
+               if (Ret != 0) {
+
+                       SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR005,
+                               SK_PNMI_ERR005MSG);
+
+                       return (SK_PNMI_ERR_GENERAL);
+               }
+               break;
+
+       case SK_PNMI_ACT_SELFTEST:
+               /*
+                * Perform a driver selftest or something similar to this.
+                * Currently this feature is not used and will probably
+                * implemented in another way.
+                */
+               Ret = SK_DRIVER_SELFTEST(pAC, IoC);
+               pAC->Pnmi.TestResult = Ret;
+               break;
+
+       case SK_PNMI_ACT_RESETCNT:
+               /* Set all counters and timestamps to zero */
+               ResetCounter(pAC, IoC, NetIndex);
+               break;
+
+       default:
+               SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR006,
+                       SK_PNMI_ERR006MSG);
+
+               return (SK_PNMI_ERR_GENERAL);
+       }
+
+       return (SK_PNMI_ERR_OK);
+}
+
+/*****************************************************************************
+ *
+ * Mac8023Stat - OID handler of OID_GEN_XXX and OID_802_3_XXX
+ *
+ * Description:
+ *     Retrieves the statistic values of the virtual port (logical
+ *     index 0). Only special OIDs of NDIS are handled which consist
+ *     of a 32 bit instead of a 64 bit value. The OIDs are public
+ *     because perhaps some other platform can use them too.
+ *
+ * Returns:
+ *     SK_PNMI_ERR_OK           The request was successfully performed.
+ *     SK_PNMI_ERR_GENERAL      A general severe internal error occured.
+ *     SK_PNMI_ERR_TOO_SHORT    The passed buffer is too short to contain
+ *                              the correct data (e.g. a 32bit value is
+ *                              needed, but a 16 bit value was passed).
+ *     SK_PNMI_ERR_UNKNOWN_INST The requested instance of the OID doesn't
+ *                           exist (e.g. port instance 3 on a two port
+ *                              adapter.
+ */
+PNMI_STATIC int Mac8023Stat(
+SK_AC *pAC,            /* Pointer to adapter context */
+SK_IOC IoC,            /* IO context handle */
+int Action,            /* GET/PRESET/SET action */
+SK_U32 Id,             /* Object ID that is to be processed */
+char *pBuf,            /* Buffer used for the management data transfer */
+unsigned int *pLen,    /* On call: pBuf buffer length. On return: used buffer */
+SK_U32 Instance,       /* Instance (1..n) that is to be queried or -1 */
+unsigned int TableIndex,       /* Index to the Id table */
+SK_U32 NetIndex)       /* NetIndex (0..n), in single net mode always zero */
+{
+       int     Ret;
+       SK_U64  StatVal;
+       SK_U32  StatVal32;
+       SK_BOOL Is64BitReq = SK_FALSE;
+
+       /*
+        * Only the active Mac is returned
+        */
+       if (Instance != (SK_U32)(-1) && Instance != 1) {
+
+               *pLen = 0;
+               return (SK_PNMI_ERR_UNKNOWN_INST);
+       }
+
+       /*
+        * Check action type
+        */
+       if (Action != SK_PNMI_GET) {
+
+               *pLen = 0;
+               return (SK_PNMI_ERR_READ_ONLY);
+       }
+
+       /* Check length */
+       switch (Id) {
+
+       case OID_802_3_PERMANENT_ADDRESS:
+       case OID_802_3_CURRENT_ADDRESS:
+               if (*pLen < sizeof(SK_MAC_ADDR)) {
+
+                       *pLen = sizeof(SK_MAC_ADDR);
+                       return (SK_PNMI_ERR_TOO_SHORT);
+               }
+               break;
+
+       default:
+#ifndef SK_NDIS_64BIT_CTR
+               if (*pLen < sizeof(SK_U32)) {
+                       *pLen = sizeof(SK_U32);
+                       return (SK_PNMI_ERR_TOO_SHORT);
+               }
+
+#else /* SK_NDIS_64BIT_CTR */
+
+               /* for compatibility, at least 32bit are required for OID */
+               if (*pLen < sizeof(SK_U32)) {
+                       /*
+                       * but indicate handling for 64bit values,
+                       * if insufficient space is provided
+                       */
+                       *pLen = sizeof(SK_U64);
+                       return (SK_PNMI_ERR_TOO_SHORT);
+               }
+
+               Is64BitReq = (*pLen < sizeof(SK_U64)) ? SK_FALSE : SK_TRUE;
+#endif /* SK_NDIS_64BIT_CTR */
+               break;
+       }
+
+       /*
+        * Update all statistics, because we retrieve virtual MAC, which
+        * consists of multiple physical statistics and increment semaphore
+        * to indicate that an update was already done.
+        */
+       Ret = MacUpdate(pAC, IoC, 0, pAC->GIni.GIMacsFound - 1);
+       if ( Ret != SK_PNMI_ERR_OK) {
+
+               *pLen = 0;
+               return (Ret);
+       }
+       pAC->Pnmi.MacUpdatedFlag ++;
+
+       /*
+        * Get value (MAC Index 0 identifies the virtual MAC)
+        */
+       switch (Id) {
+
+       case OID_802_3_PERMANENT_ADDRESS:
+               CopyMac(pBuf, &pAC->Addr.Net[NetIndex].PermanentMacAddress);
+               *pLen = sizeof(SK_MAC_ADDR);
+               break;
+
+       case OID_802_3_CURRENT_ADDRESS:
+               CopyMac(pBuf, &pAC->Addr.Net[NetIndex].CurrentMacAddress);
+               *pLen = sizeof(SK_MAC_ADDR);
+               break;
+
+       default:
+               StatVal = GetStatVal(pAC, IoC, 0, IdTable[TableIndex].Param, NetIndex);
+
+               /* by default 32bit values are evaluated */
+               if (!Is64BitReq) {
+                       StatVal32 = (SK_U32)StatVal;
+                       SK_PNMI_STORE_U32(pBuf, StatVal32);
+                       *pLen = sizeof(SK_U32);
+               }
+               else {
+                       SK_PNMI_STORE_U64(pBuf, StatVal);
+                       *pLen = sizeof(SK_U64);
+               }
+               break;
+       }
+
+       pAC->Pnmi.MacUpdatedFlag --;
+
+       return (SK_PNMI_ERR_OK);
+}
+
+/*****************************************************************************
+ *
+ * MacPrivateStat - OID handler function of OID_SKGE_STAT_XXX
+ *
+ * Description:
+ *     Retrieves the MAC statistic data.
+ *
+ * Returns:
+ *     SK_PNMI_ERR_OK           The request was successfully performed.
+ *     SK_PNMI_ERR_GENERAL      A general severe internal error occured.
+ *     SK_PNMI_ERR_TOO_SHORT    The passed buffer is too short to contain
+ *                              the correct data (e.g. a 32bit value is
+ *                              needed, but a 16 bit value was passed).
+ *     SK_PNMI_ERR_UNKNOWN_INST The requested instance of the OID doesn't
+ *                           exist (e.g. port instance 3 on a two port
+ *                              adapter.
+ */
+PNMI_STATIC int MacPrivateStat(
+SK_AC *pAC,            /* Pointer to adapter context */
+SK_IOC IoC,            /* IO context handle */
+int Action,            /* GET/PRESET/SET action */
+SK_U32 Id,             /* Object ID that is to be processed */
+char *pBuf,            /* Buffer used for the management data transfer */
+unsigned int *pLen,    /* On call: pBuf buffer length. On return: used buffer */
+SK_U32 Instance,       /* Instance (1..n) that is to be queried or -1 */
+unsigned int TableIndex, /* Index to the Id table */
+SK_U32 NetIndex)       /* NetIndex (0..n), in single net mode always zero */
+{
+       unsigned int    LogPortMax;
+       unsigned int    LogPortIndex;
+       unsigned int    PhysPortMax;
+       unsigned int    Limit;
+       unsigned int    Offset;
+       int                             MacType;
+       int                             Ret;
+       SK_U64                  StatVal;
+       
+       
+
+       /* Calculate instance if wished. MAC index 0 is the virtual MAC */
+       PhysPortMax = pAC->GIni.GIMacsFound;
+       LogPortMax = SK_PNMI_PORT_PHYS2LOG(PhysPortMax);
+       
+       MacType = pAC->GIni.GIMacType;
+
+       if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) { /* Dual net mode */
+               LogPortMax--;
+       }
+
+       if ((Instance != (SK_U32)(-1))) { /* Only one specific instance is queried */
+               /* Check instance range */
+               if ((Instance < 1) || (Instance > LogPortMax)) {
+
+                       *pLen = 0;
+                       return (SK_PNMI_ERR_UNKNOWN_INST);
+               }
+               LogPortIndex = SK_PNMI_PORT_INST2LOG(Instance);
+               Limit = LogPortIndex + 1;
+       }
+
+       else { /* Instance == (SK_U32)(-1), get all Instances of that OID */
+
+               LogPortIndex = 0;
+               Limit = LogPortMax;
+       }
+
+       /* Check action */
+       if (Action != SK_PNMI_GET) {
+
+               *pLen = 0;
+               return (SK_PNMI_ERR_READ_ONLY);
+       }
+
+       /* Check length */
+       if (*pLen < (Limit - LogPortIndex) * sizeof(SK_U64)) {
+
+               *pLen = (Limit - LogPortIndex) * sizeof(SK_U64);
+               return (SK_PNMI_ERR_TOO_SHORT);
+       }
+
+       /*
+        * Update MAC statistic and increment semaphore to indicate that
+        * an update was already done.
+        */
+       Ret = MacUpdate(pAC, IoC, 0, pAC->GIni.GIMacsFound - 1);
+       if (Ret != SK_PNMI_ERR_OK) {
+
+               *pLen = 0;
+               return (Ret);
+       }
+       pAC->Pnmi.MacUpdatedFlag ++;
+
+       /* Get value */
+       Offset = 0;
+       for (; LogPortIndex < Limit; LogPortIndex ++) {
+
+               switch (Id) {
+
+/* XXX not yet implemented due to XMAC problems
+               case OID_SKGE_STAT_TX_UTIL:
+                       return (SK_PNMI_ERR_GENERAL);
+*/
+/* XXX not yet implemented due to XMAC problems
+               case OID_SKGE_STAT_RX_UTIL:
+                       return (SK_PNMI_ERR_GENERAL);
+*/
+               case OID_SKGE_STAT_RX:
+                       if (MacType == SK_MAC_GMAC) {
+                               StatVal =
+                                       GetStatVal(pAC, IoC, LogPortIndex,
+                                                          SK_PNMI_HRX_BROADCAST, NetIndex) +
+                                       GetStatVal(pAC, IoC, LogPortIndex,
+                                                          SK_PNMI_HRX_MULTICAST, NetIndex) +
+                                       GetStatVal(pAC, IoC, LogPortIndex,
+                                                          SK_PNMI_HRX_UNICAST, NetIndex) +
+                                       GetStatVal(pAC, IoC, LogPortIndex,
+                                                          SK_PNMI_HRX_UNDERSIZE, NetIndex);
+                       }
+                       else {
+                               StatVal = GetStatVal(pAC, IoC, LogPortIndex,
+                                       IdTable[TableIndex].Param, NetIndex);
+                       }
+                       break;
+
+               case OID_SKGE_STAT_TX:
+                       if (MacType == SK_MAC_GMAC) {
+                               StatVal =
+                                       GetStatVal(pAC, IoC, LogPortIndex,
+                                                          SK_PNMI_HTX_BROADCAST, NetIndex) +
+                                       GetStatVal(pAC, IoC, LogPortIndex,
+                                                          SK_PNMI_HTX_MULTICAST, NetIndex) +
+                                       GetStatVal(pAC, IoC, LogPortIndex,
+                                                          SK_PNMI_HTX_UNICAST, NetIndex);
+                       }
+                       else {
+                               StatVal = GetStatVal(pAC, IoC, LogPortIndex,
+                                       IdTable[TableIndex].Param, NetIndex);
+                       }
+                       break;
+
+               default:
+                       StatVal = GetStatVal(pAC, IoC, LogPortIndex,
+                               IdTable[TableIndex].Param, NetIndex);
+               }
+               SK_PNMI_STORE_U64(pBuf + Offset, StatVal);
+
+               Offset += sizeof(SK_U64);
+       }
+       *pLen = Offset;
+
+       pAC->Pnmi.MacUpdatedFlag --;
+
+       return (SK_PNMI_ERR_OK);
+}
+
+/*****************************************************************************
+ *
+ * Addr - OID handler function of OID_SKGE_PHYS_CUR_ADDR and _FAC_ADDR
+ *
+ * Description:
+ *     Get/Presets/Sets the current and factory MAC address. The MAC
+ *     address of the virtual port, which is reported to the OS, may
+ *     not be changed, but the physical ones. A set to the virtual port
+ *     will be ignored. No error should be reported because otherwise
+ *     a multiple instance set (-1) would always fail.
+ *
+ * Returns:
+ *     SK_PNMI_ERR_OK           The request was successfully performed.
+ *     SK_PNMI_ERR_GENERAL      A general severe internal error occured.
+ *     SK_PNMI_ERR_TOO_SHORT    The passed buffer is too short to contain
+ *                              the correct data (e.g. a 32bit value is
+ *                              needed, but a 16 bit value was passed).
+ *     SK_PNMI_ERR_BAD_VALUE    The passed value is not in the valid
+ *                              value range.
+ *     SK_PNMI_ERR_READ_ONLY    The OID is read-only and cannot be set.
+ *     SK_PNMI_ERR_UNKNOWN_INST The requested instance of the OID doesn't
+ *                           exist (e.g. port instance 3 on a two port
+ *                              adapter.
+ */
+PNMI_STATIC int Addr(
+SK_AC *pAC,            /* Pointer to adapter context */
+SK_IOC IoC,            /* IO context handle */
+int Action,            /* GET/PRESET/SET action */
+SK_U32 Id,             /* Object ID that is to be processed */
+char *pBuf,            /* Buffer used for the management data transfer */
+unsigned int *pLen,    /* On call: pBuf buffer length. On return: used buffer */
+SK_U32 Instance,       /* Instance (1..n) that is to be queried or -1 */
+unsigned int TableIndex, /* Index to the Id table */
+SK_U32 NetIndex)       /* NetIndex (0..n), in single net mode always zero */
+{
+       int             Ret;
+       unsigned int    LogPortMax;
+       unsigned int    PhysPortMax;
+       unsigned int    LogPortIndex;
+       unsigned int    PhysPortIndex;
+       unsigned int    Limit;
+       unsigned int    Offset = 0;
+
+       /*
+        * Calculate instance if wished. MAC index 0 is the virtual
+        * MAC.
+        */
+       PhysPortMax = pAC->GIni.GIMacsFound;
+       LogPortMax = SK_PNMI_PORT_PHYS2LOG(PhysPortMax);
+
+       if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) { /* Dual net mode */
+               LogPortMax--;
+       }
+
+       if ((Instance != (SK_U32)(-1))) { /* Only one specific instance is queried */
+               /* Check instance range */
+               if ((Instance < 1) || (Instance > LogPortMax)) {
+
+                       *pLen = 0;
+                       return (SK_PNMI_ERR_UNKNOWN_INST);
+               }
+               LogPortIndex = SK_PNMI_PORT_INST2LOG(Instance);
+               Limit = LogPortIndex + 1;
+       }
+       else { /* Instance == (SK_U32)(-1), get all Instances of that OID */
+
+               LogPortIndex = 0;
+               Limit = LogPortMax;
+       }
+
+       /*
+        * Perform Action
+        */
+       if (Action == SK_PNMI_GET) {
+
+               /* Check length */
+               if (*pLen < (Limit - LogPortIndex) * 6) {
+
+                       *pLen = (Limit - LogPortIndex) * 6;
+                       return (SK_PNMI_ERR_TOO_SHORT);
+               }
+
+               /*
+                * Get value
+                */
+               for (; LogPortIndex < Limit; LogPortIndex ++) {
+
+                       switch (Id) {
+
+                       case OID_SKGE_PHYS_CUR_ADDR:
+                               if (LogPortIndex == 0) {
+                                       CopyMac(pBuf + Offset, &pAC->Addr.Net[NetIndex].CurrentMacAddress);
+                               }
+                               else {
+                                       PhysPortIndex = SK_PNMI_PORT_LOG2PHYS(pAC, LogPortIndex);
+
+                                       CopyMac(pBuf + Offset,
+                                               &pAC->Addr.Port[PhysPortIndex].CurrentMacAddress);
+                               }
+                               Offset += 6;
+                               break;
+
+                       case OID_SKGE_PHYS_FAC_ADDR:
+                               if (LogPortIndex == 0) {
+                                       CopyMac(pBuf + Offset,
+                                               &pAC->Addr.Net[NetIndex].PermanentMacAddress);
+                               }
+                               else {
+                                       PhysPortIndex = SK_PNMI_PORT_LOG2PHYS(
+                                               pAC, LogPortIndex);
+
+                                       CopyMac(pBuf + Offset,
+                                               &pAC->Addr.Port[PhysPortIndex].PermanentMacAddress);
+                               }
+                               Offset += 6;
+                               break;
+
+                       default:
+                               SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR008,
+                                       SK_PNMI_ERR008MSG);
+
+                               *pLen = 0;
+                               return (SK_PNMI_ERR_GENERAL);
+                       }
+               }
+
+               *pLen = Offset;
+       }
+       else {
+               /*
+                * The logical MAC address may not be changed only
+                * the physical ones
+                */
+               if (Id == OID_SKGE_PHYS_FAC_ADDR) {
+
+                       *pLen = 0;
+                       return (SK_PNMI_ERR_READ_ONLY);
+               }
+
+               /*
+                * Only the current address may be changed
+                */
+               if (Id != OID_SKGE_PHYS_CUR_ADDR) {
+
+                       SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR009,
+                               SK_PNMI_ERR009MSG);
+
+                       *pLen = 0;
+                       return (SK_PNMI_ERR_GENERAL);
+               }
+
+               /* Check length */
+               if (*pLen < (Limit - LogPortIndex) * 6) {
+
+                       *pLen = (Limit - LogPortIndex) * 6;
+                       return (SK_PNMI_ERR_TOO_SHORT);
+               }
+               if (*pLen > (Limit - LogPortIndex) * 6) {
+
+                       *pLen = 0;
+                       return (SK_PNMI_ERR_BAD_VALUE);
+               }
+
+               /*
+                * Check Action
+                */
+               if (Action == SK_PNMI_PRESET) {
+
+                       *pLen = 0;
+                       return (SK_PNMI_ERR_OK);
+               }
+
+               /*
+                * Set OID_SKGE_MAC_CUR_ADDR
+                */
+               for (; LogPortIndex < Limit; LogPortIndex ++, Offset += 6) {
+
+                       /*
+                        * A set to virtual port and set of broadcast
+                        * address will be ignored
+                        */
+                       if (LogPortIndex == 0 || SK_MEMCMP(pBuf + Offset,
+                               "\xff\xff\xff\xff\xff\xff", 6) == 0) {
+
+                               continue;
+                       }
+
+                       PhysPortIndex = SK_PNMI_PORT_LOG2PHYS(pAC,
+                               LogPortIndex);
+
+                       Ret = SkAddrOverride(pAC, IoC, PhysPortIndex,
+                               (SK_MAC_ADDR *)(pBuf + Offset),
+                               (LogPortIndex == 0 ? SK_ADDR_VIRTUAL_ADDRESS :
+                               SK_ADDR_PHYSICAL_ADDRESS));
+                       if (Ret != SK_ADDR_OVERRIDE_SUCCESS) {
+
+                               return (SK_PNMI_ERR_GENERAL);
+                       }
+               }
+               *pLen = Offset;
+       }
+
+       return (SK_PNMI_ERR_OK);
+}
+
+/*****************************************************************************
+ *
+ * CsumStat - OID handler function of OID_SKGE_CHKSM_XXX
+ *
+ * Description:
+ *     Retrieves the statistic values of the CSUM module. The CSUM data
+ *     structure must be available in the SK_AC even if the CSUM module
+ *     is not included, because PNMI reads the statistic data from the
+ *     CSUM part of SK_AC directly.
+ *
+ * Returns:
+ *     SK_PNMI_ERR_OK           The request was successfully performed.
+ *     SK_PNMI_ERR_GENERAL      A general severe internal error occured.
+ *     SK_PNMI_ERR_TOO_SHORT    The passed buffer is too short to contain
+ *                              the correct data (e.g. a 32bit value is
+ *                              needed, but a 16 bit value was passed).
+ *     SK_PNMI_ERR_UNKNOWN_INST The requested instance of the OID doesn't
+ *                           exist (e.g. port instance 3 on a two port
+ *                              adapter.
+ */
+PNMI_STATIC int CsumStat(
+SK_AC *pAC,            /* Pointer to adapter context */
+SK_IOC IoC,            /* IO context handle */
+int Action,            /* GET/PRESET/SET action */
+SK_U32 Id,             /* Object ID that is to be processed */
+char *pBuf,            /* Buffer used for the management data transfer */
+unsigned int *pLen,    /* On call: pBuf buffer length. On return: used buffer */
+SK_U32 Instance,       /* Instance (1..n) that is to be queried or -1 */
+unsigned int TableIndex, /* Index to the Id table */
+SK_U32 NetIndex)       /* NetIndex (0..n), in single net mode always zero */
+{
+       unsigned int    Index;
+       unsigned int    Limit;
+       unsigned int    Offset = 0;
+       SK_U64          StatVal;
+
+
+       /*
+        * Calculate instance if wished
+        */
+       if (Instance != (SK_U32)(-1)) {
+
+               if ((Instance < 1) || (Instance > SKCS_NUM_PROTOCOLS)) {
+
+                       *pLen = 0;
+                       return (SK_PNMI_ERR_UNKNOWN_INST);
+               }
+               Index = (unsigned int)Instance - 1;
+               Limit = Index + 1;
+       }
+       else {
+               Index = 0;
+               Limit = SKCS_NUM_PROTOCOLS;
+       }
+
+       /*
+        * Check action
+        */
+       if (Action != SK_PNMI_GET) {
+
+               *pLen = 0;
+               return (SK_PNMI_ERR_READ_ONLY);
+       }
+
+       /* Check length */
+       if (*pLen < (Limit - Index) * sizeof(SK_U64)) {
+
+               *pLen = (Limit - Index) * sizeof(SK_U64);
+               return (SK_PNMI_ERR_TOO_SHORT);
+       }
+
+       /*
+        * Get value
+        */
+       for (; Index < Limit; Index ++) {
+
+               switch (Id) {
+
+               case OID_SKGE_CHKSM_RX_OK_CTS:
+                       StatVal = pAC->Csum.ProtoStats[NetIndex][Index].RxOkCts;
+                       break;
+
+               case OID_SKGE_CHKSM_RX_UNABLE_CTS:
+                       StatVal = pAC->Csum.ProtoStats[NetIndex][Index].RxUnableCts;
+                       break;
+
+               case OID_SKGE_CHKSM_RX_ERR_CTS:
+                       StatVal = pAC->Csum.ProtoStats[NetIndex][Index].RxErrCts;
+                       break;
+
+               case OID_SKGE_CHKSM_TX_OK_CTS:
+                       StatVal = pAC->Csum.ProtoStats[NetIndex][Index].TxOkCts;
+                       break;
+
+               case OID_SKGE_CHKSM_TX_UNABLE_CTS:
+                       StatVal = pAC->Csum.ProtoStats[NetIndex][Index].TxUnableCts;
+                       break;
+
+               default:
+                       SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR010,
+                               SK_PNMI_ERR010MSG);
+
+                       *pLen = 0;
+                       return (SK_PNMI_ERR_GENERAL);
+               }
+
+               SK_PNMI_STORE_U64(pBuf + Offset, StatVal);
+               Offset += sizeof(SK_U64);
+       }
+
+       /*
+        * Store used buffer space
+        */
+       *pLen = Offset;
+
+       return (SK_PNMI_ERR_OK);
+}
+
+/*****************************************************************************
+ *
+ * SensorStat - OID handler function of OID_SKGE_SENSOR_XXX
+ *
+ * Description:
+ *     Retrieves the statistic values of the I2C module, which handles
+ *     the temperature and voltage sensors.
+ *
+ * Returns:
+ *     SK_PNMI_ERR_OK           The request was successfully performed.
+ *     SK_PNMI_ERR_GENERAL      A general severe internal error occured.
+ *     SK_PNMI_ERR_TOO_SHORT    The passed buffer is too short to contain
+ *                              the correct data (e.g. a 32bit value is
+ *                              needed, but a 16 bit value was passed).
+ *     SK_PNMI_ERR_UNKNOWN_INST The requested instance of the OID doesn't
+ *                           exist (e.g. port instance 3 on a two port
+ *                              adapter.
+ */
+PNMI_STATIC int SensorStat(
+SK_AC *pAC,            /* Pointer to adapter context */
+SK_IOC IoC,            /* IO context handle */
+int Action,            /* GET/PRESET/SET action */
+SK_U32 Id,             /* Object ID that is to be processed */
+char *pBuf,            /* Buffer used for the management data transfer */
+unsigned int *pLen,    /* On call: pBuf buffer length. On return: used buffer */
+SK_U32 Instance,       /* Instance (1..n) that is to be queried or -1 */
+unsigned int TableIndex, /* Index to the Id table */
+SK_U32 NetIndex)       /* NetIndex (0..n), in single net mode always zero */
+{
+       unsigned int    i;
+       unsigned int    Index;
+       unsigned int    Limit;
+       unsigned int    Offset;
+       unsigned int    Len;
+       SK_U32          Val32;
+       SK_U64          Val64;
+
+
+       /*
+        * Calculate instance if wished
+        */
+       if ((Instance != (SK_U32)(-1))) {
+
+               if ((Instance < 1) || (Instance > (SK_U32)pAC->I2c.MaxSens)) {
+
+                       *pLen = 0;
+                       return (SK_PNMI_ERR_UNKNOWN_INST);
+               }
+
+               Index = (unsigned int)Instance -1;
+               Limit = (unsigned int)Instance;
+       }
+       else {
+               Index = 0;
+               Limit = (unsigned int) pAC->I2c.MaxSens;
+       }
+
+       /*
+        * Check action
+        */
+       if (Action != SK_PNMI_GET) {
+
+               *pLen = 0;
+               return (SK_PNMI_ERR_READ_ONLY);
+       }
+
+       /* Check length */
+       switch (Id) {
+
+       case OID_SKGE_SENSOR_VALUE:
+       case OID_SKGE_SENSOR_WAR_THRES_LOW:
+       case OID_SKGE_SENSOR_WAR_THRES_UPP:
+       case OID_SKGE_SENSOR_ERR_THRES_LOW:
+       case OID_SKGE_SENSOR_ERR_THRES_UPP:
+               if (*pLen < (Limit - Index) * sizeof(SK_U32)) {
+
+                       *pLen = (Limit - Index) * sizeof(SK_U32);
+                       return (SK_PNMI_ERR_TOO_SHORT);
+               }
+               break;
+
+       case OID_SKGE_SENSOR_DESCR:
+               for (Offset = 0, i = Index; i < Limit; i ++) {
+
+                       Len = (unsigned int)
+                               SK_STRLEN(pAC->I2c.SenTable[i].SenDesc) + 1;
+                       if (Len >= SK_PNMI_STRINGLEN2) {
+
+                               SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR011,
+                                       SK_PNMI_ERR011MSG);
+
+                               *pLen = 0;
+                               return (SK_PNMI_ERR_GENERAL);
+                       }
+                       Offset += Len;
+               }
+               if (*pLen < Offset) {
+
+                       *pLen = Offset;
+                       return (SK_PNMI_ERR_TOO_SHORT);
+               }
+               break;
+
+       case OID_SKGE_SENSOR_INDEX:
+       case OID_SKGE_SENSOR_TYPE:
+       case OID_SKGE_SENSOR_STATUS:
+               if (*pLen < Limit - Index) {
+
+                       *pLen = Limit - Index;
+                       return (SK_PNMI_ERR_TOO_SHORT);
+               }
+               break;
+
+       case OID_SKGE_SENSOR_WAR_CTS:
+       case OID_SKGE_SENSOR_WAR_TIME:
+       case OID_SKGE_SENSOR_ERR_CTS:
+       case OID_SKGE_SENSOR_ERR_TIME:
+               if (*pLen < (Limit - Index) * sizeof(SK_U64)) {
+
+                       *pLen = (Limit - Index) * sizeof(SK_U64);
+                       return (SK_PNMI_ERR_TOO_SHORT);
+               }
+               break;
+
+       default:
+               SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR012,
+                       SK_PNMI_ERR012MSG);
+
+               *pLen = 0;
+               return (SK_PNMI_ERR_GENERAL);
+
+       }
+
+       /*
+        * Get value
+        */
+       for (Offset = 0; Index < Limit; Index ++) {
+
+               switch (Id) {
+
+               case OID_SKGE_SENSOR_INDEX:
+                       *(pBuf + Offset) = (char)Index;
+                       Offset += sizeof(char);
+                       break;
+
+               case OID_SKGE_SENSOR_DESCR:
+                       Len = SK_STRLEN(pAC->I2c.SenTable[Index].SenDesc);
+                       SK_MEMCPY(pBuf + Offset + 1,
+                               pAC->I2c.SenTable[Index].SenDesc, Len);
+                       *(pBuf + Offset) = (char)Len;
+                       Offset += Len + 1;
+                       break;
+
+               case OID_SKGE_SENSOR_TYPE:
+                       *(pBuf + Offset) =
+                               (char)pAC->I2c.SenTable[Index].SenType;
+                       Offset += sizeof(char);
+                       break;
+
+               case OID_SKGE_SENSOR_VALUE:
+                       Val32 = (SK_U32)pAC->I2c.SenTable[Index].SenValue;
+                       SK_PNMI_STORE_U32(pBuf + Offset, Val32);
+                       Offset += sizeof(SK_U32);
+                       break;
+
+               case OID_SKGE_SENSOR_WAR_THRES_LOW:
+                       Val32 = (SK_U32)pAC->I2c.SenTable[Index].
+                               SenThreWarnLow;
+                       SK_PNMI_STORE_U32(pBuf + Offset, Val32);
+                       Offset += sizeof(SK_U32);
+                       break;
+
+               case OID_SKGE_SENSOR_WAR_THRES_UPP:
+                       Val32 = (SK_U32)pAC->I2c.SenTable[Index].
+                               SenThreWarnHigh;
+                       SK_PNMI_STORE_U32(pBuf + Offset, Val32);
+                       Offset += sizeof(SK_U32);
+                       break;
+
+               case OID_SKGE_SENSOR_ERR_THRES_LOW:
+                       Val32 = (SK_U32)pAC->I2c.SenTable[Index].
+                               SenThreErrLow;
+                       SK_PNMI_STORE_U32(pBuf + Offset, Val32);
+                       Offset += sizeof(SK_U32);
+                       break;
+
+               case OID_SKGE_SENSOR_ERR_THRES_UPP:
+                       Val32 = pAC->I2c.SenTable[Index].SenThreErrHigh;
+                       SK_PNMI_STORE_U32(pBuf + Offset, Val32);
+                       Offset += sizeof(SK_U32);
+                       break;
+
+               case OID_SKGE_SENSOR_STATUS:
+                       *(pBuf + Offset) =
+                               (char)pAC->I2c.SenTable[Index].SenErrFlag;
+                       Offset += sizeof(char);
+                       break;
+
+               case OID_SKGE_SENSOR_WAR_CTS:
+                       Val64 = pAC->I2c.SenTable[Index].SenWarnCts;
+                       SK_PNMI_STORE_U64(pBuf + Offset, Val64);
+                       Offset += sizeof(SK_U64);
+                       break;
+
+               case OID_SKGE_SENSOR_ERR_CTS:
+                       Val64 = pAC->I2c.SenTable[Index].SenErrCts;
+                       SK_PNMI_STORE_U64(pBuf + Offset, Val64);
+                       Offset += sizeof(SK_U64);
+                       break;
+
+               case OID_SKGE_SENSOR_WAR_TIME:
+                       Val64 = SK_PNMI_HUNDREDS_SEC(pAC->I2c.SenTable[Index].
+                               SenBegWarnTS);
+                       SK_PNMI_STORE_U64(pBuf + Offset, Val64);
+                       Offset += sizeof(SK_U64);
+                       break;
+
+               case OID_SKGE_SENSOR_ERR_TIME:
+                       Val64 = SK_PNMI_HUNDREDS_SEC(pAC->I2c.SenTable[Index].
+                               SenBegErrTS);
+                       SK_PNMI_STORE_U64(pBuf + Offset, Val64);
+                       Offset += sizeof(SK_U64);
+                       break;
+
+               default:
+                       SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_ERR,
+                               ("SensorStat: Unknown OID should be handled before"));
+
+                       return (SK_PNMI_ERR_GENERAL);
+               }
+       }
+
+       /*
+        * Store used buffer space
+        */
+       *pLen = Offset;
+
+       return (SK_PNMI_ERR_OK);
+}
+
+/*****************************************************************************
+ *
+ * Vpd - OID handler function of OID_SKGE_VPD_XXX
+ *
+ * Description:
+ *     Get/preset/set of VPD data. As instance the name of a VPD key
+ *     can be passed. The Instance parameter is a SK_U32 and can be
+ *     used as a string buffer for the VPD key, because their maximum
+ *     length is 4 byte.
+ *
+ * Returns:
+ *     SK_PNMI_ERR_OK           The request was successfully performed.
+ *     SK_PNMI_ERR_GENERAL      A general severe internal error occured.
+ *     SK_PNMI_ERR_TOO_SHORT    The passed buffer is too short to contain
+ *                              the correct data (e.g. a 32bit value is
+ *                              needed, but a 16 bit value was passed).
+ *     SK_PNMI_ERR_BAD_VALUE    The passed value is not in the valid
+ *                              value range.
+ *     SK_PNMI_ERR_READ_ONLY    The OID is read-only and cannot be set.
+ *     SK_PNMI_ERR_UNKNOWN_INST The requested instance of the OID doesn't
+ *                           exist (e.g. port instance 3 on a two port
+ *                              adapter.
+ */
+PNMI_STATIC int Vpd(
+SK_AC *pAC,            /* Pointer to adapter context */
+SK_IOC IoC,            /* IO context handle */
+int Action,            /* GET/PRESET/SET action */
+SK_U32 Id,             /* Object ID that is to be processed */
+char *pBuf,            /* Buffer used for the management data transfer */
+unsigned int *pLen,    /* On call: pBuf buffer length. On return: used buffer */
+SK_U32 Instance,       /* Instance (1..n) that is to be queried or -1 */
+unsigned int TableIndex, /* Index to the Id table */
+SK_U32 NetIndex)       /* NetIndex (0..n), in single net mode always zero */
+{
+       SK_VPD_STATUS   *pVpdStatus;
+       unsigned int    BufLen;
+       char            Buf[256];
+       char            KeyArr[SK_PNMI_VPD_ENTRIES][SK_PNMI_VPD_KEY_SIZE];
+       char            KeyStr[SK_PNMI_VPD_KEY_SIZE];
+       unsigned int    KeyNo;
+       unsigned int    Offset;
+       unsigned int    Index;
+       unsigned int    FirstIndex;
+       unsigned int    LastIndex;
+       unsigned int    Len;
+       int             Ret;
+       SK_U32          Val32;
+
+       /*
+        * Get array of all currently stored VPD keys
+        */
+       Ret = GetVpdKeyArr(pAC, IoC, &KeyArr[0][0], sizeof(KeyArr), &KeyNo);
+       if (Ret != SK_PNMI_ERR_OK) {
+               *pLen = 0;
+               return (Ret);
+       }
+
+       /*
+        * If instance is not -1, try to find the requested VPD key for
+        * the multiple instance variables. The other OIDs as for example
+        * OID VPD_ACTION are single instance variables and must be
+        * handled separatly.
+        */
+       FirstIndex = 0;
+       LastIndex = KeyNo;
+
+       if ((Instance != (SK_U32)(-1))) {
+
+               if (Id == OID_SKGE_VPD_KEY || Id == OID_SKGE_VPD_VALUE ||
+                       Id == OID_SKGE_VPD_ACCESS) {
+
+                       SK_STRNCPY(KeyStr, (char *)&Instance, 4);
+                       KeyStr[4] = 0;
+
+                       for (Index = 0; Index < KeyNo; Index ++) {
+
+                               if (SK_STRCMP(KeyStr, KeyArr[Index]) == 0) {
+                                       FirstIndex = Index;
+                                       LastIndex = Index+1;
+                                       break;
+                               }
+                       }
+                       if (Index == KeyNo) {
+
+                               *pLen = 0;
+                               return (SK_PNMI_ERR_UNKNOWN_INST);
+                       }
+               }
+               else if (Instance != 1) {
+
+                       *pLen = 0;
+                       return (SK_PNMI_ERR_UNKNOWN_INST);
+               }
+       }
+
+       /*
+        * Get value, if a query should be performed
+        */
+       if (Action == SK_PNMI_GET) {
+
+               switch (Id) {
+
+               case OID_SKGE_VPD_FREE_BYTES:
+                       /* Check length of buffer */
+                       if (*pLen < sizeof(SK_U32)) {
+
+                               *pLen = sizeof(SK_U32);
+                               return (SK_PNMI_ERR_TOO_SHORT);
+                       }
+                       /* Get number of free bytes */
+                       pVpdStatus = VpdStat(pAC, IoC);
+                       if (pVpdStatus == NULL) {
+
+                               SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR017,
+                                       SK_PNMI_ERR017MSG);
+
+                               *pLen = 0;
+                               return (SK_PNMI_ERR_GENERAL);
+                       }
+                       if ((pVpdStatus->vpd_status & VPD_VALID) == 0) {
+
+                               SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR018,
+                                       SK_PNMI_ERR018MSG);
+
+                               *pLen = 0;
+                               return (SK_PNMI_ERR_GENERAL);
+                       }
+                       
+                       Val32 = (SK_U32)pVpdStatus->vpd_free_rw;
+                       SK_PNMI_STORE_U32(pBuf, Val32);
+                       *pLen = sizeof(SK_U32);
+                       break;
+
+               case OID_SKGE_VPD_ENTRIES_LIST:
+                       /* Check length */
+                       for (Len = 0, Index = 0; Index < KeyNo; Index ++) {
+
+                               Len += SK_STRLEN(KeyArr[Index]) + 1;
+                       }
+                       if (*pLen < Len) {
+
+                               *pLen = Len;
+                               return (SK_PNMI_ERR_TOO_SHORT);
+                       }
+
+                       /* Get value */
+                       *(pBuf) = (char)Len - 1;
+                       for (Offset = 1, Index = 0; Index < KeyNo; Index ++) {
+
+                               Len = SK_STRLEN(KeyArr[Index]);
+                               SK_MEMCPY(pBuf + Offset, KeyArr[Index], Len);
+
+                               Offset += Len;
+
+                               if (Index < KeyNo - 1) {
+
+                                       *(pBuf + Offset) = ' ';
+                                       Offset ++;
+                               }
+                       }
+                       *pLen = Offset;
+                       break;
+
+               case OID_SKGE_VPD_ENTRIES_NUMBER:
+                       /* Check length */
+                       if (*pLen < sizeof(SK_U32)) {
+
+                               *pLen = sizeof(SK_U32);
+                               return (SK_PNMI_ERR_TOO_SHORT);
+                       }
+
+                       Val32 = (SK_U32)KeyNo;
+                       SK_PNMI_STORE_U32(pBuf, Val32);
+                       *pLen = sizeof(SK_U32);
+                       break;
+
+               case OID_SKGE_VPD_KEY:
+                       /* Check buffer length, if it is large enough */
+                       for (Len = 0, Index = FirstIndex;
+                               Index < LastIndex; Index ++) {
+
+                               Len += SK_STRLEN(KeyArr[Index]) + 1;
+                       }
+                       if (*pLen < Len) {
+
+                               *pLen = Len;
+                               return (SK_PNMI_ERR_TOO_SHORT);
+                       }
+
+                       /*
+                        * Get the key to an intermediate buffer, because
+                        * we have to prepend a length byte.
+                        */
+                       for (Offset = 0, Index = FirstIndex;
+                               Index < LastIndex; Index ++) {
+
+                               Len = SK_STRLEN(KeyArr[Index]);
+
+                               *(pBuf + Offset) = (char)Len;
+                               SK_MEMCPY(pBuf + Offset + 1, KeyArr[Index],
+                                       Len);
+                               Offset += Len + 1;
+                       }
+                       *pLen = Offset;
+                       break;
+
+               case OID_SKGE_VPD_VALUE:
+                       /* Check the buffer length if it is large enough */
+                       for (Offset = 0, Index = FirstIndex;
+                               Index < LastIndex; Index ++) {
+
+                               BufLen = 256;
+                               if (VpdRead(pAC, IoC, KeyArr[Index], Buf,
+                                       (int *)&BufLen) > 0 ||
+                                       BufLen >= SK_PNMI_VPD_DATALEN) {
+
+                                       SK_ERR_LOG(pAC, SK_ERRCL_SW,
+                                               SK_PNMI_ERR021,
+                                               SK_PNMI_ERR021MSG);
+
+                                       return (SK_PNMI_ERR_GENERAL);
+                               }
+                               Offset += BufLen + 1;
+                       }
+                       if (*pLen < Offset) {
+
+                               *pLen = Offset;
+                               return (SK_PNMI_ERR_TOO_SHORT);
+                       }
+
+                       /*
+                        * Get the value to an intermediate buffer, because
+                        * we have to prepend a length byte.
+                        */
+                       for (Offset = 0, Index = FirstIndex;
+                               Index < LastIndex; Index ++) {
+
+                               BufLen = 256;
+                               if (VpdRead(pAC, IoC, KeyArr[Index], Buf,
+                                       (int *)&BufLen) > 0 ||
+                                       BufLen >= SK_PNMI_VPD_DATALEN) {
+
+                                       SK_ERR_LOG(pAC, SK_ERRCL_SW,
+                                               SK_PNMI_ERR022,
+                                               SK_PNMI_ERR022MSG);
+
+                                       *pLen = 0;
+                                       return (SK_PNMI_ERR_GENERAL);
+                               }
+
+                               *(pBuf + Offset) = (char)BufLen;
+                               SK_MEMCPY(pBuf + Offset + 1, Buf, BufLen);
+                               Offset += BufLen + 1;
+                       }
+                       *pLen = Offset;
+                       break;
+
+               case OID_SKGE_VPD_ACCESS:
+                       if (*pLen < LastIndex - FirstIndex) {
+
+                               *pLen = LastIndex - FirstIndex;
+                               return (SK_PNMI_ERR_TOO_SHORT);
+                       }
+
+                       for (Offset = 0, Index = FirstIndex;
+                               Index < LastIndex; Index ++) {
+
+                               if (VpdMayWrite(KeyArr[Index])) {
+
+                                       *(pBuf + Offset) = SK_PNMI_VPD_RW;
+                               }
+                               else {
+                                       *(pBuf + Offset) = SK_PNMI_VPD_RO;
+                               }
+                               Offset ++;
+                       }
+                       *pLen = Offset;
+                       break;
+
+               case OID_SKGE_VPD_ACTION:
+                       Offset = LastIndex - FirstIndex;
+                       if (*pLen < Offset) {
+
+                               *pLen = Offset;
+                               return (SK_PNMI_ERR_TOO_SHORT);
+                       }
+                       SK_MEMSET(pBuf, 0, Offset);
+                       *pLen = Offset;
+                       break;
+
+               default:
+                       SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR023,
+                               SK_PNMI_ERR023MSG);
+
+                       *pLen = 0;
+                       return (SK_PNMI_ERR_GENERAL);
+               }
+       }
+       else {
+               /* The only OID which can be set is VPD_ACTION */
+               if (Id != OID_SKGE_VPD_ACTION) {
+
+                       if (Id == OID_SKGE_VPD_FREE_BYTES ||
+                               Id == OID_SKGE_VPD_ENTRIES_LIST ||
+                               Id == OID_SKGE_VPD_ENTRIES_NUMBER ||
+                               Id == OID_SKGE_VPD_KEY ||
+                               Id == OID_SKGE_VPD_VALUE ||
+                               Id == OID_SKGE_VPD_ACCESS) {
+
+                               *pLen = 0;
+                               return (SK_PNMI_ERR_READ_ONLY);
+                       }
+
+                       SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR024,
+                               SK_PNMI_ERR024MSG);
+
+                       *pLen = 0;
+                       return (SK_PNMI_ERR_GENERAL);
+               }
+
+               /*
+                * From this point we handle VPD_ACTION. Check the buffer
+                * length. It should at least have the size of one byte.
+                */
+               if (*pLen < 1) {
+
+                       *pLen = 1;
+                       return (SK_PNMI_ERR_TOO_SHORT);
+               }
+
+               /*
+                * The first byte contains the VPD action type we should
+                * perform.
+                */
+               switch (*pBuf) {
+
+               case SK_PNMI_VPD_IGNORE:
+                       /* Nothing to do */
+                       break;
+
+               case SK_PNMI_VPD_CREATE:
+                       /*
+                        * We have to create a new VPD entry or we modify
+                        * an existing one. Check first the buffer length.
+                        */
+                       if (*pLen < 4) {
+
+                               *pLen = 4;
+                               return (SK_PNMI_ERR_TOO_SHORT);
+                       }
+                       KeyStr[0] = pBuf[1];
+                       KeyStr[1] = pBuf[2];
+                       KeyStr[2] = 0;
+
+                       /*
+                        * Is the entry writable or does it belong to the
+                        * read-only area?
+                        */
+                       if (!VpdMayWrite(KeyStr)) {
+
+                               *pLen = 0;
+                               return (SK_PNMI_ERR_BAD_VALUE);
+                       }
+
+                       Offset = (int)pBuf[3] & 0xFF;
+
+                       SK_MEMCPY(Buf, pBuf + 4, Offset);
+                       Buf[Offset] = 0;
+
+                       /* A preset ends here */
+                       if (Action == SK_PNMI_PRESET) {
+
+                               return (SK_PNMI_ERR_OK);
+                       }
+
+                       /* Write the new entry or modify an existing one */
+                       Ret = VpdWrite(pAC, IoC, KeyStr, Buf);
+                       if (Ret == SK_PNMI_VPD_NOWRITE ) {
+
+                               *pLen = 0;
+                               return (SK_PNMI_ERR_BAD_VALUE);
+                       }
+                       else if (Ret != SK_PNMI_VPD_OK) {
+
+                               SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR025,
+                                       SK_PNMI_ERR025MSG);
+
+                               *pLen = 0;
+                               return (SK_PNMI_ERR_GENERAL);
+                       }
+
+                       /*
+                        * Perform an update of the VPD data. This is
+                        * not mandantory, but just to be sure.
+                        */
+                       Ret = VpdUpdate(pAC, IoC);
+                       if (Ret != SK_PNMI_VPD_OK) {
+
+                               SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR026,
+                                       SK_PNMI_ERR026MSG);
+
+                               *pLen = 0;
+                               return (SK_PNMI_ERR_GENERAL);
+                       }
+                       break;
+
+               case SK_PNMI_VPD_DELETE:
+                       /* Check if the buffer size is plausible */
+                       if (*pLen < 3) {
+
+                               *pLen = 3;
+                               return (SK_PNMI_ERR_TOO_SHORT);
+                       }
+                       if (*pLen > 3) {
+
+                               *pLen = 0;
+                               return (SK_PNMI_ERR_BAD_VALUE);
+                       }
+                       KeyStr[0] = pBuf[1];
+                       KeyStr[1] = pBuf[2];
+                       KeyStr[2] = 0;
+
+                       /* Find the passed key in the array */
+                       for (Index = 0; Index < KeyNo; Index ++) {
+
+                               if (SK_STRCMP(KeyStr, KeyArr[Index]) == 0) {
+
+                                       break;
+                               }
+                       }
+                       /*
+                        * If we cannot find the key it is wrong, so we
+                        * return an appropriate error value.
+                        */
+                       if (Index == KeyNo) {
+
+                               *pLen = 0;
+                               return (SK_PNMI_ERR_BAD_VALUE);
+                       }
+
+                       if (Action == SK_PNMI_PRESET) {
+
+                               return (SK_PNMI_ERR_OK);
+                       }
+
+                       /* Ok, you wanted it and you will get it */
+                       Ret = VpdDelete(pAC, IoC, KeyStr);
+                       if (Ret != SK_PNMI_VPD_OK) {
+
+                               SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR027,
+                                       SK_PNMI_ERR027MSG);
+
+                               *pLen = 0;
+                               return (SK_PNMI_ERR_GENERAL);
+                       }
+
+                       /*
+                        * Perform an update of the VPD data. This is
+                        * not mandantory, but just to be sure.
+                        */
+                       Ret = VpdUpdate(pAC, IoC);
+                       if (Ret != SK_PNMI_VPD_OK) {
+
+                               SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR028,
+                                       SK_PNMI_ERR028MSG);
+
+                               *pLen = 0;
+                               return (SK_PNMI_ERR_GENERAL);
+                       }
+                       break;
+
+               default:
+                       *pLen = 0;
+                       return (SK_PNMI_ERR_BAD_VALUE);
+               }
+       }
+
+       return (SK_PNMI_ERR_OK);
+}
+
+/*****************************************************************************
+ *
+ * General - OID handler function of various single instance OIDs
+ *
+ * Description:
+ *     The code is simple. No description necessary.
+ *
+ * Returns:
+ *     SK_PNMI_ERR_OK           The request was successfully performed.
+ *     SK_PNMI_ERR_GENERAL      A general severe internal error occured.
+ *     SK_PNMI_ERR_TOO_SHORT    The passed buffer is too short to contain
+ *                              the correct data (e.g. a 32bit value is
+ *                              needed, but a 16 bit value was passed).
+ *     SK_PNMI_ERR_UNKNOWN_INST The requested instance of the OID doesn't
+ *                           exist (e.g. port instance 3 on a two port
+ *                              adapter.
+ */
+PNMI_STATIC int General(
+SK_AC *pAC,            /* Pointer to adapter context */
+SK_IOC IoC,            /* IO context handle */
+int Action,            /* GET/PRESET/SET action */
+SK_U32 Id,             /* Object ID that is to be processed */
+char *pBuf,            /* Buffer used for the management data transfer */
+unsigned int *pLen,    /* On call: buffer length. On return: used buffer */
+SK_U32 Instance,       /* Instance (1..n) that is to be queried or -1 */
+unsigned int TableIndex, /* Index to the Id table */
+SK_U32 NetIndex)       /* NetIndex (0..n), in single net mode always zero */
+{
+       int             Ret;
+       unsigned int    Index;
+       unsigned int    Len;
+       unsigned int    Offset;
+       unsigned int    Val;
+       SK_U8           Val8;
+       SK_U16          Val16;
+       SK_U32          Val32;
+       SK_U64          Val64;
+       SK_U64          Val64RxHwErrs = 0;
+       SK_U64          Val64TxHwErrs = 0;
+       SK_BOOL         Is64BitReq = SK_FALSE;
+       char            Buf[256];
+       int                     MacType;
+
+       /*
+        * Check instance. We only handle single instance variables.
+        */
+       if (Instance != (SK_U32)(-1) && Instance != 1) {
+
+               *pLen = 0;
+               return (SK_PNMI_ERR_UNKNOWN_INST);
+       }
+
+       /*
+        * Check action. We only allow get requests.
+        */
+       if (Action != SK_PNMI_GET) {
+
+               *pLen = 0;
+               return (SK_PNMI_ERR_READ_ONLY);
+       }
+       
+       MacType = pAC->GIni.GIMacType;
+       
+       /*
+        * Check length for the various supported OIDs
+        */
+       switch (Id) {
+
+       case OID_GEN_XMIT_ERROR:
+       case OID_GEN_RCV_ERROR:
+       case OID_GEN_RCV_NO_BUFFER:
+#ifndef SK_NDIS_64BIT_CTR
+               if (*pLen < sizeof(SK_U32)) {
+                       *pLen = sizeof(SK_U32);
+                       return (SK_PNMI_ERR_TOO_SHORT);
+               }
+
+#else /* SK_NDIS_64BIT_CTR */
+
+               /*
+                * for compatibility, at least 32bit are required for oid
+                */
+               if (*pLen < sizeof(SK_U32)) {
+                       /*
+                       * but indicate handling for 64bit values,
+                       * if insufficient space is provided
+                       */
+                       *pLen = sizeof(SK_U64);
+                       return (SK_PNMI_ERR_TOO_SHORT);
+               }
+
+               Is64BitReq = (*pLen < sizeof(SK_U64)) ? SK_FALSE : SK_TRUE;
+#endif /* SK_NDIS_64BIT_CTR */
+               break;
+
+       case OID_SKGE_PORT_NUMBER:
+       case OID_SKGE_DEVICE_TYPE:
+       case OID_SKGE_RESULT:
+       case OID_SKGE_RLMT_MONITOR_NUMBER:
+       case OID_GEN_TRANSMIT_QUEUE_LENGTH:
+       case OID_SKGE_TRAP_NUMBER:
+       case OID_SKGE_MDB_VERSION:
+       case OID_SKGE_BOARDLEVEL:
+       case OID_SKGE_CHIPID:
+       case OID_SKGE_RAMSIZE:
+               if (*pLen < sizeof(SK_U32)) {
+
+                       *pLen = sizeof(SK_U32);
+                       return (SK_PNMI_ERR_TOO_SHORT);
+               }
+               break;
+
+       case OID_SKGE_CHIPSET:
+               if (*pLen < sizeof(SK_U16)) {
+
+                       *pLen = sizeof(SK_U16);
+                       return (SK_PNMI_ERR_TOO_SHORT);
+               }
+               break;
+
+       case OID_SKGE_BUS_TYPE:
+       case OID_SKGE_BUS_SPEED:
+       case OID_SKGE_BUS_WIDTH:
+       case OID_SKGE_SENSOR_NUMBER:
+       case OID_SKGE_CHKSM_NUMBER:
+       case OID_SKGE_VAUXAVAIL:
+               if (*pLen < sizeof(SK_U8)) {
+
+                       *pLen = sizeof(SK_U8);
+                       return (SK_PNMI_ERR_TOO_SHORT);
+               }
+               break;
+
+       case OID_SKGE_TX_SW_QUEUE_LEN:
+       case OID_SKGE_TX_SW_QUEUE_MAX:
+       case OID_SKGE_TX_RETRY:
+       case OID_SKGE_RX_INTR_CTS:
+       case OID_SKGE_TX_INTR_CTS:
+       case OID_SKGE_RX_NO_BUF_CTS:
+       case OID_SKGE_TX_NO_BUF_CTS:
+       case OID_SKGE_TX_USED_DESCR_NO:
+       case OID_SKGE_RX_DELIVERED_CTS:
+       case OID_SKGE_RX_OCTETS_DELIV_CTS:
+       case OID_SKGE_RX_HW_ERROR_CTS:
+       case OID_SKGE_TX_HW_ERROR_CTS:
+       case OID_SKGE_IN_ERRORS_CTS:
+       case OID_SKGE_OUT_ERROR_CTS:
+       case OID_SKGE_ERR_RECOVERY_CTS:
+       case OID_SKGE_SYSUPTIME:
+               if (*pLen < sizeof(SK_U64)) {
+
+                       *pLen = sizeof(SK_U64);
+                       return (SK_PNMI_ERR_TOO_SHORT);
+               }
+               break;
+
+       default:
+               /* Checked later */
+               break;
+       }
+
+       /* Update statistic */
+       if (Id == OID_SKGE_RX_HW_ERROR_CTS ||
+               Id == OID_SKGE_TX_HW_ERROR_CTS ||
+               Id == OID_SKGE_IN_ERRORS_CTS ||
+               Id == OID_SKGE_OUT_ERROR_CTS ||
+               Id == OID_GEN_XMIT_ERROR ||
+               Id == OID_GEN_RCV_ERROR) {
+
+               /* Force the XMAC to update its statistic counters and
+                * Increment semaphore to indicate that an update was
+                * already done.
+                */
+               Ret = MacUpdate(pAC, IoC, 0, pAC->GIni.GIMacsFound - 1);
+               if (Ret != SK_PNMI_ERR_OK) {
+
+                       *pLen = 0;
+                       return (Ret);
+               }
+               pAC->Pnmi.MacUpdatedFlag ++;
+
+               /*
+                * Some OIDs consist of multiple hardware counters. Those
+                * values which are contained in all of them will be added
+                * now.
+                */
+               switch (Id) {
+
+               case OID_SKGE_RX_HW_ERROR_CTS:
+               case OID_SKGE_IN_ERRORS_CTS:
+               case OID_GEN_RCV_ERROR:
+                       Val64RxHwErrs =
+                               GetStatVal(pAC, IoC, 0, SK_PNMI_HRX_MISSED, NetIndex) +
+                               GetStatVal(pAC, IoC, 0, SK_PNMI_HRX_FRAMING, NetIndex) +
+                               GetStatVal(pAC, IoC, 0, SK_PNMI_HRX_OVERFLOW, NetIndex) +
+                               GetStatVal(pAC, IoC, 0, SK_PNMI_HRX_JABBER, NetIndex) +
+                               GetStatVal(pAC, IoC, 0, SK_PNMI_HRX_CARRIER, NetIndex) +
+                               GetStatVal(pAC, IoC, 0, SK_PNMI_HRX_IRLENGTH, NetIndex) +
+                               GetStatVal(pAC, IoC, 0, SK_PNMI_HRX_SYMBOL, NetIndex) +
+                               GetStatVal(pAC, IoC, 0, SK_PNMI_HRX_SHORTS, NetIndex) +
+                               GetStatVal(pAC, IoC, 0, SK_PNMI_HRX_RUNT, NetIndex) +
+                               GetStatVal(pAC, IoC, 0, SK_PNMI_HRX_TOO_LONG, NetIndex) +
+                               GetStatVal(pAC, IoC, 0, SK_PNMI_HRX_FCS, NetIndex) +
+                               GetStatVal(pAC, IoC, 0, SK_PNMI_HRX_CEXT, NetIndex);
+               break;
+
+               case OID_SKGE_TX_HW_ERROR_CTS:
+               case OID_SKGE_OUT_ERROR_CTS:
+               case OID_GEN_XMIT_ERROR:
+                       Val64TxHwErrs =
+                               GetStatVal(pAC, IoC, 0, SK_PNMI_HTX_EXCESS_COL, NetIndex) +
+                               GetStatVal(pAC, IoC, 0, SK_PNMI_HTX_LATE_COL, NetIndex) +
+                               GetStatVal(pAC, IoC, 0, SK_PNMI_HTX_UNDERRUN, NetIndex) +
+                               GetStatVal(pAC, IoC, 0, SK_PNMI_HTX_CARRIER, NetIndex);
+                       break;
+               }
+       }
+
+       /*
+        * Retrieve value
+        */
+       switch (Id) {
+
+       case OID_SKGE_SUPPORTED_LIST:
+               Len = ID_TABLE_SIZE * sizeof(SK_U32);
+               if (*pLen < Len) {
+
+                       *pLen = Len;
+                       return (SK_PNMI_ERR_TOO_SHORT);
+               }
+               for (Offset = 0, Index = 0; Offset < Len;
+                       Offset += sizeof(SK_U32), Index ++) {
+
+                       Val32 = (SK_U32)IdTable[Index].Id;
+                       SK_PNMI_STORE_U32(pBuf + Offset, Val32);
+               }
+               *pLen = Len;
+               break;
+
+       case OID_SKGE_BOARDLEVEL:
+               Val32 = (SK_U32)pAC->GIni.GILevel;
+               SK_PNMI_STORE_U32(pBuf, Val32);
+               *pLen = sizeof(SK_U32);
+               break;
+
+       case OID_SKGE_PORT_NUMBER:
+               Val32 = (SK_U32)pAC->GIni.GIMacsFound;
+               SK_PNMI_STORE_U32(pBuf, Val32);
+               *pLen = sizeof(SK_U32);
+               break;
+
+       case OID_SKGE_DEVICE_TYPE:
+               Val32 = (SK_U32)pAC->Pnmi.DeviceType;
+               SK_PNMI_STORE_U32(pBuf, Val32);
+               *pLen = sizeof(SK_U32);
+               break;
+
+       case OID_SKGE_DRIVER_DESCR:
+               if (pAC->Pnmi.pDriverDescription == NULL) {
+
+                       SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR007,
+                               SK_PNMI_ERR007MSG);
+
+                       *pLen = 0;
+                       return (SK_PNMI_ERR_GENERAL);
+               }
+
+               Len = SK_STRLEN(pAC->Pnmi.pDriverDescription) + 1;
+               if (Len > SK_PNMI_STRINGLEN1) {
+
+                       SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR029,
+                               SK_PNMI_ERR029MSG);
+
+                       *pLen = 0;
+                       return (SK_PNMI_ERR_GENERAL);
+               }
+
+               if (*pLen < Len) {
+
+                       *pLen = Len;
+                       return (SK_PNMI_ERR_TOO_SHORT);
+               }
+               *pBuf = (char)(Len - 1);
+               SK_MEMCPY(pBuf + 1, pAC->Pnmi.pDriverDescription, Len - 1);
+               *pLen = Len;
+               break;
+
+       case OID_SKGE_DRIVER_VERSION:
+               if (pAC->Pnmi.pDriverVersion == NULL) {
+
+                       SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR030,
+                               SK_PNMI_ERR030MSG);
+
+                       *pLen = 0;
+                       return (SK_PNMI_ERR_GENERAL);
+               }
+
+               Len = SK_STRLEN(pAC->Pnmi.pDriverVersion) + 1;
+               if (Len > SK_PNMI_STRINGLEN1) {
+
+                       SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR031,
+                               SK_PNMI_ERR031MSG);
+
+                       *pLen = 0;
+                       return (SK_PNMI_ERR_GENERAL);
+               }
+
+               if (*pLen < Len) {
+
+                       *pLen = Len;
+                       return (SK_PNMI_ERR_TOO_SHORT);
+               }
+               *pBuf = (char)(Len - 1);
+               SK_MEMCPY(pBuf + 1, pAC->Pnmi.pDriverVersion, Len - 1);
+               *pLen = Len;
+               break;
+
+       case OID_SKGE_DRIVER_RELDATE:
+               if (pAC->Pnmi.pDriverReleaseDate == NULL) {
+
+                       SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR030,
+                               SK_PNMI_ERR053MSG);
+
+                       *pLen = 0;
+                       return (SK_PNMI_ERR_GENERAL);
+               }
+
+               Len = SK_STRLEN(pAC->Pnmi.pDriverReleaseDate) + 1;
+               if (Len > SK_PNMI_STRINGLEN1) {
+
+                       SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR031,
+                               SK_PNMI_ERR054MSG);
+
+                       *pLen = 0;
+                       return (SK_PNMI_ERR_GENERAL);
+               }
+
+               if (*pLen < Len) {
+
+                       *pLen = Len;
+                       return (SK_PNMI_ERR_TOO_SHORT);
+               }
+               *pBuf = (char)(Len - 1);
+               SK_MEMCPY(pBuf + 1, pAC->Pnmi.pDriverReleaseDate, Len - 1);
+               *pLen = Len;
+               break;
+
+       case OID_SKGE_DRIVER_FILENAME:
+               if (pAC->Pnmi.pDriverFileName == NULL) {
+
+                       SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR030,
+                               SK_PNMI_ERR055MSG);
+
+                       *pLen = 0;
+                       return (SK_PNMI_ERR_GENERAL);
+               }
+
+               Len = SK_STRLEN(pAC->Pnmi.pDriverFileName) + 1;
+               if (Len > SK_PNMI_STRINGLEN1) {
+
+                       SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR031,
+                               SK_PNMI_ERR056MSG);
+
+                       *pLen = 0;
+                       return (SK_PNMI_ERR_GENERAL);
+               }
+
+               if (*pLen < Len) {
+
+                       *pLen = Len;
+                       return (SK_PNMI_ERR_TOO_SHORT);
+               }
+               *pBuf = (char)(Len - 1);
+               SK_MEMCPY(pBuf + 1, pAC->Pnmi.pDriverFileName, Len - 1);
+               *pLen = Len;
+               break;
+
+       case OID_SKGE_HW_DESCR:
+               /*
+                * The hardware description is located in the VPD. This
+                * query may move to the initialisation routine. But
+                * the VPD data is cached and therefore a call here
+                * will not make much difference.
+                */
+               Len = 256;
+               if (VpdRead(pAC, IoC, VPD_NAME, Buf, (int *)&Len) > 0) {
+
+                       SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR032,
+                               SK_PNMI_ERR032MSG);
+
+                       *pLen = 0;
+                       return (SK_PNMI_ERR_GENERAL);
+               }
+               Len ++;
+               if (Len > SK_PNMI_STRINGLEN1) {
+
+                       SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR033,
+                               SK_PNMI_ERR033MSG);
+
+                       *pLen = 0;
+                       return (SK_PNMI_ERR_GENERAL);
+               }
+               if (*pLen < Len) {
+
+                       *pLen = Len;
+                       return (SK_PNMI_ERR_TOO_SHORT);
+               }
+               *pBuf = (char)(Len - 1);
+               SK_MEMCPY(pBuf + 1, Buf, Len - 1);
+               *pLen = Len;
+               break;
+
+       case OID_SKGE_HW_VERSION:
+               /* Oh, I love to do some string manipulation */
+               if (*pLen < 5) {
+
+                       *pLen = 5;
+                       return (SK_PNMI_ERR_TOO_SHORT);
+               }
+               Val8 = (SK_U8)pAC->GIni.GIPciHwRev;
+               pBuf[0] = 4;
+               pBuf[1] = 'v';
+               pBuf[2] = (char)(0x30 | ((Val8 >> 4) & 0x0F));
+               pBuf[3] = '.';
+               pBuf[4] = (char)(0x30 | (Val8 & 0x0F));
+               *pLen = 5;
+               break;
+
+       case OID_SKGE_CHIPSET:
+               Val16 = pAC->Pnmi.Chipset;
+               SK_PNMI_STORE_U16(pBuf, Val16);
+               *pLen = sizeof(SK_U16);
+               break;
+
+       case OID_SKGE_CHIPID:
+               Val32 = pAC->GIni.GIChipId;
+               SK_PNMI_STORE_U32(pBuf, Val32);
+               *pLen = sizeof(SK_U32);
+               break;
+
+       case OID_SKGE_RAMSIZE:
+               Val32 = pAC->GIni.GIRamSize;
+               SK_PNMI_STORE_U32(pBuf, Val32);
+               *pLen = sizeof(SK_U32);
+               break;
+
+       case OID_SKGE_VAUXAVAIL:
+               *pBuf = (char) pAC->GIni.GIVauxAvail;
+               *pLen = sizeof(char);
+               break;
+
+       case OID_SKGE_BUS_TYPE:
+               *pBuf = (char) SK_PNMI_BUS_PCI;
+               *pLen = sizeof(char);
+               break;
+
+       case OID_SKGE_BUS_SPEED:
+               *pBuf = pAC->Pnmi.PciBusSpeed;
+               *pLen = sizeof(char);
+               break;
+
+       case OID_SKGE_BUS_WIDTH:
+               *pBuf = pAC->Pnmi.PciBusWidth;
+               *pLen = sizeof(char);
+               break;
+
+       case OID_SKGE_RESULT:
+               Val32 = pAC->Pnmi.TestResult;
+               SK_PNMI_STORE_U32(pBuf, Val32);
+               *pLen = sizeof(SK_U32);
+               break;
+
+       case OID_SKGE_SENSOR_NUMBER:
+               *pBuf = (char)pAC->I2c.MaxSens;
+               *pLen = sizeof(char);
+               break;
+
+       case OID_SKGE_CHKSM_NUMBER:
+               *pBuf = SKCS_NUM_PROTOCOLS;
+               *pLen = sizeof(char);
+               break;
+
+       case OID_SKGE_TRAP_NUMBER:
+               GetTrapQueueLen(pAC, &Len, &Val);
+               Val32 = (SK_U32)Val;
+               SK_PNMI_STORE_U32(pBuf, Val32);
+               *pLen = sizeof(SK_U32);
+               break;
+
+       case OID_SKGE_TRAP:
+               GetTrapQueueLen(pAC, &Len, &Val);
+               if (*pLen < Len) {
+
+                       *pLen = Len;
+                       return (SK_PNMI_ERR_TOO_SHORT);
+               }
+               CopyTrapQueue(pAC, pBuf);
+               *pLen = Len;
+               break;
+
+       case OID_SKGE_RLMT_MONITOR_NUMBER:
+/* XXX Not yet implemented by RLMT therefore we return zero elements */
+               Val32 = 0;
+               SK_PNMI_STORE_U32(pBuf, Val32);
+               *pLen = sizeof(SK_U32);
+               break;
+
+       case OID_SKGE_TX_SW_QUEUE_LEN:
+               /* 2002-09-17 pweber: For XMAC, use the frozen SW counters (BufPort) */
+               if (MacType == SK_MAC_XMAC) {
+                       /* Dual net mode */
+                       if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) {
+                               Val64 = pAC->Pnmi.BufPort[NetIndex].TxSwQueueLen;
+                       }
+                       /* Single net mode */
+                       else {
+                               Val64 = pAC->Pnmi.BufPort[0].TxSwQueueLen +
+                                       pAC->Pnmi.BufPort[1].TxSwQueueLen;
+                       }                       
+               }
+               else {
+                       /* Dual net mode */
+                       if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) {
+                               Val64 = pAC->Pnmi.Port[NetIndex].TxSwQueueLen;
+                       }
+                       /* Single net mode */
+                       else {
+                               Val64 = pAC->Pnmi.Port[0].TxSwQueueLen +
+                                       pAC->Pnmi.Port[1].TxSwQueueLen;
+                       }                       
+               }
+               SK_PNMI_STORE_U64(pBuf, Val64);
+               *pLen = sizeof(SK_U64);
+               break;
+
+
+       case OID_SKGE_TX_SW_QUEUE_MAX:
+               /* 2002-09-17 pweber: For XMAC, use the frozen SW counters (BufPort) */
+               if (MacType == SK_MAC_XMAC) {
+                       /* Dual net mode */
+                       if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) {
+                               Val64 = pAC->Pnmi.BufPort[NetIndex].TxSwQueueMax;
+                       }
+                       /* Single net mode */
+                       else {
+                               Val64 = pAC->Pnmi.BufPort[0].TxSwQueueMax +
+                                       pAC->Pnmi.BufPort[1].TxSwQueueMax;
+                       }
+               }
+               else {
+                       /* Dual net mode */
+                       if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) {
+                               Val64 = pAC->Pnmi.Port[NetIndex].TxSwQueueMax;
+                       }
+                       /* Single net mode */
+                       else {
+                               Val64 = pAC->Pnmi.Port[0].TxSwQueueMax +
+                                       pAC->Pnmi.Port[1].TxSwQueueMax;
+                       }
+               }
+               SK_PNMI_STORE_U64(pBuf, Val64);
+               *pLen = sizeof(SK_U64);
+               break;
+
+       case OID_SKGE_TX_RETRY:
+               /* 2002-09-17 pweber: For XMAC, use the frozen SW counters (BufPort) */
+               if (MacType == SK_MAC_XMAC) {
+                       /* Dual net mode */
+                       if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) {
+                               Val64 = pAC->Pnmi.BufPort[NetIndex].TxRetryCts;
+                       }
+                       /* Single net mode */
+                       else {
+                               Val64 = pAC->Pnmi.BufPort[0].TxRetryCts +
+                                       pAC->Pnmi.BufPort[1].TxRetryCts;
+                       }
+               }
+               else {
+                       /* Dual net mode */
+                       if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) {
+                               Val64 = pAC->Pnmi.Port[NetIndex].TxRetryCts;
+                       }
+                       /* Single net mode */
+                       else {
+                               Val64 = pAC->Pnmi.Port[0].TxRetryCts +
+                                       pAC->Pnmi.Port[1].TxRetryCts;
+                       }
+               }
+               SK_PNMI_STORE_U64(pBuf, Val64);
+               *pLen = sizeof(SK_U64);
+               break;
+
+       case OID_SKGE_RX_INTR_CTS:
+               /* 2002-09-17 pweber: For XMAC, use the frozen SW counters (BufPort) */
+               if (MacType == SK_MAC_XMAC) {
+                       /* Dual net mode */
+                       if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) {
+                               Val64 = pAC->Pnmi.BufPort[NetIndex].RxIntrCts;
+                       }
+                       /* Single net mode */
+                       else {
+                               Val64 = pAC->Pnmi.BufPort[0].RxIntrCts +
+                                       pAC->Pnmi.BufPort[1].RxIntrCts;
+                       }
+               }
+               else {
+                       /* Dual net mode */
+                       if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) {
+                               Val64 = pAC->Pnmi.Port[NetIndex].RxIntrCts;
+                       }
+                       /* Single net mode */
+                       else {
+                               Val64 = pAC->Pnmi.Port[0].RxIntrCts +
+                                       pAC->Pnmi.Port[1].RxIntrCts;
+                       }
+               }
+               SK_PNMI_STORE_U64(pBuf, Val64);
+               *pLen = sizeof(SK_U64);
+               break;
+
+       case OID_SKGE_TX_INTR_CTS:
+               /* 2002-09-17 pweber: For XMAC, use the frozen SW counters (BufPort) */
+               if (MacType == SK_MAC_XMAC) {
+                       /* Dual net mode */
+                       if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) {
+                               Val64 = pAC->Pnmi.BufPort[NetIndex].TxIntrCts;
+                       }
+                       /* Single net mode */
+                       else {
+                               Val64 = pAC->Pnmi.BufPort[0].TxIntrCts +
+                                       pAC->Pnmi.BufPort[1].TxIntrCts;
+                       }
+               }
+               else {
+                       /* Dual net mode */
+                       if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) {
+                               Val64 = pAC->Pnmi.Port[NetIndex].TxIntrCts;
+                       }
+                       /* Single net mode */
+                       else {
+                               Val64 = pAC->Pnmi.Port[0].TxIntrCts +
+                                       pAC->Pnmi.Port[1].TxIntrCts;
+                       }
+               }
+               SK_PNMI_STORE_U64(pBuf, Val64);
+               *pLen = sizeof(SK_U64);
+               break;
+
+       case OID_SKGE_RX_NO_BUF_CTS:
+               /* 2002-09-17 pweber: For XMAC, use the frozen SW counters (BufPort) */
+               if (MacType == SK_MAC_XMAC) {
+                       /* Dual net mode */
+                       if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) {
+                               Val64 = pAC->Pnmi.BufPort[NetIndex].RxNoBufCts;
+                       }
+                       /* Single net mode */
+                       else {
+                               Val64 = pAC->Pnmi.BufPort[0].RxNoBufCts +
+                                       pAC->Pnmi.BufPort[1].RxNoBufCts;
+                       }
+               }
+               else {
+                       /* Dual net mode */
+                       if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) {
+                               Val64 = pAC->Pnmi.Port[NetIndex].RxNoBufCts;
+                       }
+                       /* Single net mode */
+                       else {
+                               Val64 = pAC->Pnmi.Port[0].RxNoBufCts +
+                                       pAC->Pnmi.Port[1].RxNoBufCts;
+                       }
+               }
+               SK_PNMI_STORE_U64(pBuf, Val64);
+               *pLen = sizeof(SK_U64);
+               break;
+
+       case OID_SKGE_TX_NO_BUF_CTS:
+               /* 2002-09-17 pweber: For XMAC, use the frozen SW counters (BufPort) */
+               if (MacType == SK_MAC_XMAC) {
+                       /* Dual net mode */
+                       if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) {
+                               Val64 = pAC->Pnmi.BufPort[NetIndex].TxNoBufCts;
+                       }
+                       /* Single net mode */
+                       else {
+                               Val64 = pAC->Pnmi.BufPort[0].TxNoBufCts +
+                                       pAC->Pnmi.BufPort[1].TxNoBufCts;
+                       }
+               }
+               else {
+                       /* Dual net mode */
+                       if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) {
+                               Val64 = pAC->Pnmi.Port[NetIndex].TxNoBufCts;
+                       }
+                       /* Single net mode */
+                       else {
+                               Val64 = pAC->Pnmi.Port[0].TxNoBufCts +
+                                       pAC->Pnmi.Port[1].TxNoBufCts;
+                       }
+               }
+               SK_PNMI_STORE_U64(pBuf, Val64);
+               *pLen = sizeof(SK_U64);
+               break;
+
+       case OID_SKGE_TX_USED_DESCR_NO:
+               /* 2002-09-17 pweber: For XMAC, use the frozen SW counters (BufPort) */
+               if (MacType == SK_MAC_XMAC) {
+                       /* Dual net mode */
+                       if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) {
+                               Val64 = pAC->Pnmi.BufPort[NetIndex].TxUsedDescrNo;
+                       }
+                       /* Single net mode */
+                       else {
+                               Val64 = pAC->Pnmi.BufPort[0].TxUsedDescrNo +
+                                       pAC->Pnmi.BufPort[1].TxUsedDescrNo;
+                       }
+               }
+               else {
+                       /* Dual net mode */
+                       if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) {
+                               Val64 = pAC->Pnmi.Port[NetIndex].TxUsedDescrNo;
+                       }
+                       /* Single net mode */
+                       else {
+                               Val64 = pAC->Pnmi.Port[0].TxUsedDescrNo +
+                                       pAC->Pnmi.Port[1].TxUsedDescrNo;
+                       }
+               }
+               SK_PNMI_STORE_U64(pBuf, Val64);
+               *pLen = sizeof(SK_U64);
+               break;
+
+       case OID_SKGE_RX_DELIVERED_CTS:
+               /* 2002-09-17 pweber: For XMAC, use the frozen SW counters (BufPort) */
+               if (MacType == SK_MAC_XMAC) {
+                       /* Dual net mode */
+                       if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) {
+                               Val64 = pAC->Pnmi.BufPort[NetIndex].RxDeliveredCts;
+                       }
+                       /* Single net mode */
+                       else {
+                               Val64 = pAC->Pnmi.BufPort[0].RxDeliveredCts +
+                                       pAC->Pnmi.BufPort[1].RxDeliveredCts;
+                       }
+               }
+               else {
+                       /* Dual net mode */
+                       if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) {
+                               Val64 = pAC->Pnmi.Port[NetIndex].RxDeliveredCts;
+                       }
+                       /* Single net mode */
+                       else {
+                               Val64 = pAC->Pnmi.Port[0].RxDeliveredCts +
+                                       pAC->Pnmi.Port[1].RxDeliveredCts;
+                       }
+               }
+               SK_PNMI_STORE_U64(pBuf, Val64);
+               *pLen = sizeof(SK_U64);
+               break;
+
+       case OID_SKGE_RX_OCTETS_DELIV_CTS:
+               /* 2002-09-17 pweber: For XMAC, use the frozen SW counters (BufPort) */
+               if (MacType == SK_MAC_XMAC) {
+                       /* Dual net mode */
+                       if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) {
+                               Val64 = pAC->Pnmi.BufPort[NetIndex].RxOctetsDeliveredCts;
+                       }
+                       /* Single net mode */
+                       else {
+                               Val64 = pAC->Pnmi.BufPort[0].RxOctetsDeliveredCts +
+                                       pAC->Pnmi.BufPort[1].RxOctetsDeliveredCts;
+                       }
+               }
+               else {
+                       /* Dual net mode */
+                       if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) {
+                               Val64 = pAC->Pnmi.Port[NetIndex].RxOctetsDeliveredCts;
+                       }
+                       /* Single net mode */
+                       else {
+                               Val64 = pAC->Pnmi.Port[0].RxOctetsDeliveredCts +
+                                       pAC->Pnmi.Port[1].RxOctetsDeliveredCts;
+                       }
+               }
+               SK_PNMI_STORE_U64(pBuf, Val64);
+               *pLen = sizeof(SK_U64);
+               break;
+
+       case OID_SKGE_RX_HW_ERROR_CTS:
+               SK_PNMI_STORE_U64(pBuf, Val64RxHwErrs);
+               *pLen = sizeof(SK_U64);
+               break;
+
+       case OID_SKGE_TX_HW_ERROR_CTS:
+               SK_PNMI_STORE_U64(pBuf, Val64TxHwErrs);
+               *pLen = sizeof(SK_U64);
+               break;
+
+       case OID_SKGE_IN_ERRORS_CTS:
+               /* 2002-09-17 pweber: For XMAC, use the frozen SW counters (BufPort) */
+               if (MacType == SK_MAC_XMAC) {
+                       /* Dual net mode */
+                       if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) {
+                               Val64 = Val64RxHwErrs + pAC->Pnmi.BufPort[NetIndex].RxNoBufCts;
+                       }
+                       /* Single net mode */
+                       else {
+                               Val64 = Val64RxHwErrs +
+                                       pAC->Pnmi.BufPort[0].RxNoBufCts +
+                                       pAC->Pnmi.BufPort[1].RxNoBufCts;
+                       }
+               }
+               else {
+                       /* Dual net mode */
+                       if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) {
+                               Val64 = Val64RxHwErrs + pAC->Pnmi.Port[NetIndex].RxNoBufCts;
+                       }
+                       /* Single net mode */
+                       else {
+                               Val64 = Val64RxHwErrs +
+                                       pAC->Pnmi.Port[0].RxNoBufCts +
+                                       pAC->Pnmi.Port[1].RxNoBufCts;
+                       }
+               }
+               SK_PNMI_STORE_U64(pBuf, Val64);
+               *pLen = sizeof(SK_U64);
+               break;
+
+       case OID_SKGE_OUT_ERROR_CTS:
+               /* 2002-09-17 pweber: For XMAC, use the frozen SW counters (BufPort) */
+               if (MacType == SK_MAC_XMAC) {
+                       /* Dual net mode */
+                       if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) {
+                               Val64 = Val64TxHwErrs + pAC->Pnmi.BufPort[NetIndex].TxNoBufCts;
+                       }
+                       /* Single net mode */
+                       else {
+                               Val64 = Val64TxHwErrs +
+                                       pAC->Pnmi.BufPort[0].TxNoBufCts +
+                                       pAC->Pnmi.BufPort[1].TxNoBufCts;
+                       }
+               }
+               else {
+                       /* Dual net mode */
+                       if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) {
+                               Val64 = Val64TxHwErrs + pAC->Pnmi.Port[NetIndex].TxNoBufCts;
+                       }
+                       /* Single net mode */
+                       else {
+                               Val64 = Val64TxHwErrs +
+                                       pAC->Pnmi.Port[0].TxNoBufCts +
+                                       pAC->Pnmi.Port[1].TxNoBufCts;
+                       }
+               }
+               SK_PNMI_STORE_U64(pBuf, Val64);
+               *pLen = sizeof(SK_U64);
+               break;
+
+       case OID_SKGE_ERR_RECOVERY_CTS:
+               /* 2002-09-17 pweber: For XMAC, use the frozen SW counters (BufPort) */
+               if (MacType == SK_MAC_XMAC) {
+                       /* Dual net mode */
+                       if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) {
+                               Val64 = pAC->Pnmi.BufPort[NetIndex].ErrRecoveryCts;
+                       }
+                       /* Single net mode */
+                       else {
+                               Val64 = pAC->Pnmi.BufPort[0].ErrRecoveryCts +
+                                       pAC->Pnmi.BufPort[1].ErrRecoveryCts;
+                       }
+               }
+               else {
+                       /* Dual net mode */
+                       if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) {
+                               Val64 = pAC->Pnmi.Port[NetIndex].ErrRecoveryCts;
+                       }
+                       /* Single net mode */
+                       else {
+                               Val64 = pAC->Pnmi.Port[0].ErrRecoveryCts +
+                                       pAC->Pnmi.Port[1].ErrRecoveryCts;
+                       }
+               }
+               SK_PNMI_STORE_U64(pBuf, Val64);
+               *pLen = sizeof(SK_U64);
+               break;
+
+       case OID_SKGE_SYSUPTIME:
+               Val64 = SK_PNMI_HUNDREDS_SEC(SkOsGetTime(pAC));
+               Val64 -= pAC->Pnmi.StartUpTime;
+               SK_PNMI_STORE_U64(pBuf, Val64);
+               *pLen = sizeof(SK_U64);
+               break;
+
+       case OID_SKGE_MDB_VERSION:
+               Val32 = SK_PNMI_MDB_VERSION;
+               SK_PNMI_STORE_U32(pBuf, Val32);
+               *pLen = sizeof(SK_U32);
+               break;
+
+       case OID_GEN_RCV_ERROR:
+               /* 2002-09-17 pweber: For XMAC, use the frozen SW counters (BufPort) */
+               if (MacType == SK_MAC_XMAC) {
+                       Val64 = Val64RxHwErrs + pAC->Pnmi.BufPort[NetIndex].RxNoBufCts;
+               }
+               else {
+                       Val64 = Val64RxHwErrs + pAC->Pnmi.Port[NetIndex].RxNoBufCts;
+               }
+
+               /*
+                * by default 32bit values are evaluated
+                */
+               if (!Is64BitReq) {
+                       Val32 = (SK_U32)Val64;
+                       SK_PNMI_STORE_U32(pBuf, Val32);
+                       *pLen = sizeof(SK_U32);
+               }
+               else {
+                       SK_PNMI_STORE_U64(pBuf, Val64);
+                       *pLen = sizeof(SK_U64);
+               }
+               break;
+
+       case OID_GEN_XMIT_ERROR:
+               /* 2002-09-17 pweber: For XMAC, use the frozen SW counters (BufPort) */
+               if (MacType == SK_MAC_XMAC) {
+                       Val64 = Val64TxHwErrs + pAC->Pnmi.BufPort[NetIndex].TxNoBufCts;
+               }
+               else {
+                       Val64 = Val64TxHwErrs + pAC->Pnmi.Port[NetIndex].TxNoBufCts;
+               }
+
+               /*
+                * by default 32bit values are evaluated
+                */
+               if (!Is64BitReq) {
+                       Val32 = (SK_U32)Val64;
+                       SK_PNMI_STORE_U32(pBuf, Val32);
+                       *pLen = sizeof(SK_U32);
+               }
+               else {
+                       SK_PNMI_STORE_U64(pBuf, Val64);
+                       *pLen = sizeof(SK_U64);
+               }
+               break;
+
+       case OID_GEN_RCV_NO_BUFFER:
+               /* 2002-09-17 pweber: For XMAC, use the frozen SW counters (BufPort) */
+               if (MacType == SK_MAC_XMAC) {
+                       Val64 = pAC->Pnmi.BufPort[NetIndex].RxNoBufCts;
+               }
+               else {
+                       Val64 = pAC->Pnmi.Port[NetIndex].RxNoBufCts;
+               }
+
+               /*
+                * by default 32bit values are evaluated
+                */
+               if (!Is64BitReq) {
+                       Val32 = (SK_U32)Val64;
+                       SK_PNMI_STORE_U32(pBuf, Val32);
+                       *pLen = sizeof(SK_U32);
+               }
+               else {
+                       SK_PNMI_STORE_U64(pBuf, Val64);
+                       *pLen = sizeof(SK_U64);
+               }
+               break;
+
+       case OID_GEN_TRANSMIT_QUEUE_LENGTH:
+               Val32 = (SK_U32)pAC->Pnmi.Port[NetIndex].TxSwQueueLen;
+               SK_PNMI_STORE_U32(pBuf, Val32);
+               *pLen = sizeof(SK_U32);
+               break;
+
+       default:
+               SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR034,
+                       SK_PNMI_ERR034MSG);
+
+               *pLen = 0;
+               return (SK_PNMI_ERR_GENERAL);
+       }
+
+       if (Id == OID_SKGE_RX_HW_ERROR_CTS ||
+               Id == OID_SKGE_TX_HW_ERROR_CTS ||
+               Id == OID_SKGE_IN_ERRORS_CTS ||
+               Id == OID_SKGE_OUT_ERROR_CTS ||
+               Id == OID_GEN_XMIT_ERROR ||
+               Id == OID_GEN_RCV_ERROR) {
+
+               pAC->Pnmi.MacUpdatedFlag --;
+       }
+
+       return (SK_PNMI_ERR_OK);
+}
+
+/*****************************************************************************
+ *
+ * Rlmt - OID handler function of OID_SKGE_RLMT_XXX single instance.
+ *
+ * Description:
+ *     Get/Presets/Sets the RLMT OIDs.
+ *
+ * Returns:
+ *     SK_PNMI_ERR_OK           The request was successfully performed.
+ *     SK_PNMI_ERR_GENERAL      A general severe internal error occured.
+ *     SK_PNMI_ERR_TOO_SHORT    The passed buffer is too short to contain
+ *                              the correct data (e.g. a 32bit value is
+ *                              needed, but a 16 bit value was passed).
+ *     SK_PNMI_ERR_BAD_VALUE    The passed value is not in the valid
+ *                              value range.
+ *     SK_PNMI_ERR_READ_ONLY    The OID is read-only and cannot be set.
+ *     SK_PNMI_ERR_UNKNOWN_INST The requested instance of the OID doesn't
+ *                           exist (e.g. port instance 3 on a two port
+ *                              adapter.
+ */
+PNMI_STATIC int Rlmt(
+SK_AC *pAC,            /* Pointer to adapter context */
+SK_IOC IoC,            /* IO context handle */
+int Action,            /* GET/PRESET/SET action */
+SK_U32 Id,             /* Object ID that is to be processed */
+char *pBuf,            /* Buffer used for the management data transfer */
+unsigned int *pLen,    /* On call: pBuf buffer length. On return: used buffer */
+SK_U32 Instance,       /* Instance (1..n) that is to be queried or -1 */
+unsigned int TableIndex, /* Index to the Id table */
+SK_U32 NetIndex)       /* NetIndex (0..n), in single net mode always zero */
+{
+       int             Ret;
+       unsigned int    PhysPortIndex;
+       unsigned int    PhysPortMax;
+       SK_EVPARA       EventParam;
+       SK_U32          Val32;
+       SK_U64          Val64;
+
+
+       /*
+        * Check instance. Only single instance OIDs are allowed here.
+        */
+       if (Instance != (SK_U32)(-1) && Instance != 1) {
+
+               *pLen = 0;
+               return (SK_PNMI_ERR_UNKNOWN_INST);
+       }
+
+       /*
+        * Perform the requested action.
+        */
+       if (Action == SK_PNMI_GET) {
+
+               /*
+                * Check if the buffer length is large enough.
+                */
+
+               switch (Id) {
+
+               case OID_SKGE_RLMT_MODE:
+               case OID_SKGE_RLMT_PORT_ACTIVE:
+               case OID_SKGE_RLMT_PORT_PREFERRED:
+                       if (*pLen < sizeof(SK_U8)) {
+
+                               *pLen = sizeof(SK_U8);
+                               return (SK_PNMI_ERR_TOO_SHORT);
+                       }
+                       break;
+
+               case OID_SKGE_RLMT_PORT_NUMBER:
+                       if (*pLen < sizeof(SK_U32)) {
+
+                               *pLen = sizeof(SK_U32);
+                               return (SK_PNMI_ERR_TOO_SHORT);
+                       }
+                       break;
+
+               case OID_SKGE_RLMT_CHANGE_CTS:
+               case OID_SKGE_RLMT_CHANGE_TIME:
+               case OID_SKGE_RLMT_CHANGE_ESTIM:
+               case OID_SKGE_RLMT_CHANGE_THRES:
+                       if (*pLen < sizeof(SK_U64)) {
+
+                               *pLen = sizeof(SK_U64);
+                               return (SK_PNMI_ERR_TOO_SHORT);
+                       }
+                       break;
+
+               default:
+                       SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR035,
+                               SK_PNMI_ERR035MSG);
+
+                       *pLen = 0;
+                       return (SK_PNMI_ERR_GENERAL);
+               }
+
+               /*
+                * Update RLMT statistic and increment semaphores to indicate
+                * that an update was already done. Maybe RLMT will hold its
+                * statistic always up to date some time. Then we can
+                * remove this type of call.
+                */
+               if ((Ret = RlmtUpdate(pAC, IoC, NetIndex)) != SK_PNMI_ERR_OK) {
+
+                       *pLen = 0;
+                       return (Ret);
+               }
+               pAC->Pnmi.RlmtUpdatedFlag ++;
+
+               /*
+                * Retrieve Value
+               */
+               switch (Id) {
+
+               case OID_SKGE_RLMT_MODE:
+                       *pBuf = (char)pAC->Rlmt.Net[0].RlmtMode;
+                       *pLen = sizeof(char);
+                       break;
+
+               case OID_SKGE_RLMT_PORT_NUMBER:
+                       Val32 = (SK_U32)pAC->GIni.GIMacsFound;
+                       SK_PNMI_STORE_U32(pBuf, Val32);
+                       *pLen = sizeof(SK_U32);
+                       break;
+
+               case OID_SKGE_RLMT_PORT_ACTIVE:
+                       *pBuf = 0;
+                       /*
+                        * If multiple ports may become active this OID
+                        * doesn't make sense any more. A new variable in
+                        * the port structure should be created. However,
+                        * for this variable the first active port is
+                        * returned.
+                        */
+                       PhysPortMax = pAC->GIni.GIMacsFound;
+
+                       for (PhysPortIndex = 0; PhysPortIndex < PhysPortMax;
+                               PhysPortIndex ++) {
+
+                               if (pAC->Pnmi.Port[PhysPortIndex].ActiveFlag) {
+
+                                       *pBuf = (char)SK_PNMI_PORT_PHYS2LOG(PhysPortIndex);
+                                       break;
+                               }
+                       }
+                       *pLen = sizeof(char);
+                       break;
+
+               case OID_SKGE_RLMT_PORT_PREFERRED:
+                       *pBuf = (char)SK_PNMI_PORT_PHYS2LOG(pAC->Rlmt.Net[NetIndex].Preference);
+                       *pLen = sizeof(char);
+                       break;
+
+               case OID_SKGE_RLMT_CHANGE_CTS:
+                       Val64 = pAC->Pnmi.RlmtChangeCts;
+                       SK_PNMI_STORE_U64(pBuf, Val64);
+                       *pLen = sizeof(SK_U64);
+                       break;
+
+               case OID_SKGE_RLMT_CHANGE_TIME:
+                       Val64 = pAC->Pnmi.RlmtChangeTime;
+                       SK_PNMI_STORE_U64(pBuf, Val64);
+                       *pLen = sizeof(SK_U64);
+                       break;
+
+               case OID_SKGE_RLMT_CHANGE_ESTIM:
+                       Val64 = pAC->Pnmi.RlmtChangeEstimate.Estimate;
+                       SK_PNMI_STORE_U64(pBuf, Val64);
+                       *pLen = sizeof(SK_U64);
+                       break;
+
+               case OID_SKGE_RLMT_CHANGE_THRES:
+                       Val64 = pAC->Pnmi.RlmtChangeThreshold;
+                       SK_PNMI_STORE_U64(pBuf, Val64);
+                       *pLen = sizeof(SK_U64);
+                       break;
+
+               default:
+                       SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_ERR,
+                               ("Rlmt: Unknown OID should be handled before"));
+
+                       pAC->Pnmi.RlmtUpdatedFlag --;
+                       *pLen = 0;
+                       return (SK_PNMI_ERR_GENERAL);
+               }
+
+               pAC->Pnmi.RlmtUpdatedFlag --;
+       }
+       else {
+               /* Perform a preset or set */
+               switch (Id) {
+
+               case OID_SKGE_RLMT_MODE:
+                       /* Check if the buffer length is plausible */
+                       if (*pLen < sizeof(char)) {
+
+                               *pLen = sizeof(char);
+                               return (SK_PNMI_ERR_TOO_SHORT);
+                       }
+                       /* Check if the value range is correct */
+                       if (*pLen != sizeof(char) ||
+                               (*pBuf & SK_PNMI_RLMT_MODE_CHK_LINK) == 0 ||
+                               *(SK_U8 *)pBuf > 15) {
+
+                               *pLen = 0;
+                               return (SK_PNMI_ERR_BAD_VALUE);
+                       }
+                       /* The preset ends here */
+                       if (Action == SK_PNMI_PRESET) {
+
+                               *pLen = 0;
+                               return (SK_PNMI_ERR_OK);
+                       }
+                       /* Send an event to RLMT to change the mode */
+                       SK_MEMSET((char *)&EventParam, 0, sizeof(EventParam));
+                       EventParam.Para32[0] |= (SK_U32)(*pBuf);
+                       EventParam.Para32[1] = 0;
+                       if (SkRlmtEvent(pAC, IoC, SK_RLMT_MODE_CHANGE,
+                               EventParam) > 0) {
+
+                               SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR037,
+                                       SK_PNMI_ERR037MSG);
+
+                               *pLen = 0;
+                               return (SK_PNMI_ERR_GENERAL);
+                       }
+                       break;
+
+               case OID_SKGE_RLMT_PORT_PREFERRED:
+                       /* Check if the buffer length is plausible */
+                       if (*pLen < sizeof(char)) {
+
+                               *pLen = sizeof(char);
+                               return (SK_PNMI_ERR_TOO_SHORT);
+                       }
+                       /* Check if the value range is correct */
+                       if (*pLen != sizeof(char) || *(SK_U8 *)pBuf >
+                               (SK_U8)pAC->GIni.GIMacsFound) {
+
+                               *pLen = 0;
+                               return (SK_PNMI_ERR_BAD_VALUE);
+                       }
+                       /* The preset ends here */
+                       if (Action == SK_PNMI_PRESET) {
+
+                               *pLen = 0;
+                               return (SK_PNMI_ERR_OK);
+                       }
+
+                       /*
+                        * Send an event to RLMT change the preferred port.
+                        * A param of -1 means automatic mode. RLMT will
+                        * make the decision which is the preferred port.
+                        */
+                       SK_MEMSET((char *)&EventParam, 0, sizeof(EventParam));
+                       EventParam.Para32[0] = (SK_U32)(*pBuf) - 1;
+                       EventParam.Para32[1] = NetIndex;
+                       if (SkRlmtEvent(pAC, IoC, SK_RLMT_PREFPORT_CHANGE,
+                               EventParam) > 0) {
+
+                               SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR038,
+                                       SK_PNMI_ERR038MSG);
+
+                               *pLen = 0;
+                               return (SK_PNMI_ERR_GENERAL);
+                       }
+                       break;
+
+               case OID_SKGE_RLMT_CHANGE_THRES:
+                       /* Check if the buffer length is plausible */
+                       if (*pLen < sizeof(SK_U64)) {
+
+                               *pLen = sizeof(SK_U64);
+                               return (SK_PNMI_ERR_TOO_SHORT);
+                       }
+                       /*
+                        * There are not many restrictions to the
+                        * value range.
+                        */
+                       if (*pLen != sizeof(SK_U64)) {
+
+                               *pLen = 0;
+                               return (SK_PNMI_ERR_BAD_VALUE);
+                       }
+                       /* A preset ends here */
+                       if (Action == SK_PNMI_PRESET) {
+
+                               *pLen = 0;
+                               return (SK_PNMI_ERR_OK);
+                       }
+                       /*
+                        * Store the new threshold, which will be taken
+                        * on the next timer event.
+                        */
+                       SK_PNMI_READ_U64(pBuf, Val64);
+                       pAC->Pnmi.RlmtChangeThreshold = Val64;
+                       break;
+
+               default:
+                       /* The other OIDs are not be able for set */
+                       *pLen = 0;
+                       return (SK_PNMI_ERR_READ_ONLY);
+               }
+       }
+
+       return (SK_PNMI_ERR_OK);
+}
+
+/*****************************************************************************
+ *
+ * RlmtStat - OID handler function of OID_SKGE_RLMT_XXX multiple instance.
+ *
+ * Description:
+ *     Performs get requests on multiple instance variables.
+ *
+ * Returns:
+ *     SK_PNMI_ERR_OK           The request was successfully performed.
+ *     SK_PNMI_ERR_GENERAL      A general severe internal error occured.
+ *     SK_PNMI_ERR_TOO_SHORT    The passed buffer is too short to contain
+ *                              the correct data (e.g. a 32bit value is
+ *                              needed, but a 16 bit value was passed).
+ *     SK_PNMI_ERR_UNKNOWN_INST The requested instance of the OID doesn't
+ *                           exist (e.g. port instance 3 on a two port
+ *                              adapter.
+ */
+PNMI_STATIC int RlmtStat(
+SK_AC *pAC,            /* Pointer to adapter context */
+SK_IOC IoC,            /* IO context handle */
+int Action,            /* GET/PRESET/SET action */
+SK_U32 Id,             /* Object ID that is to be processed */
+char *pBuf,            /* Buffer used for the management data transfer */
+unsigned int *pLen,    /* On call: pBuf buffer length. On return: used buffer */
+SK_U32 Instance,       /* Instance (1..n) that is to be queried or -1 */
+unsigned int TableIndex, /* Index to the Id table */
+SK_U32 NetIndex)       /* NetIndex (0..n), in single net mode always zero */
+{
+       unsigned int    PhysPortMax;
+       unsigned int    PhysPortIndex;
+       unsigned int    Limit;
+       unsigned int    Offset;
+       int             Ret;
+       SK_U32          Val32;
+       SK_U64          Val64;
+
+       /*
+        * Calculate the port indexes from the instance.
+        */
+       PhysPortMax = pAC->GIni.GIMacsFound;
+
+       if ((Instance != (SK_U32)(-1))) {
+               /* Check instance range */
+               if ((Instance < 1) || (Instance > PhysPortMax)) {
+
+                       *pLen = 0;
+                       return (SK_PNMI_ERR_UNKNOWN_INST);
+               }
+
+               /* Single net mode */
+               PhysPortIndex = Instance - 1;
+
+               /* Dual net mode */
+               if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) {
+                       PhysPortIndex = NetIndex;
+               }
+
+               /* Both net modes */
+               Limit = PhysPortIndex + 1;
+       }
+       else {
+               /* Single net mode */
+               PhysPortIndex = 0;
+               Limit = PhysPortMax;
+
+               /* Dual net mode */
+               if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) {
+                       PhysPortIndex = NetIndex;
+                       Limit = PhysPortIndex + 1;
+               }
+       }
+
+       /*
+        * Currently only get requests are allowed.
+        */
+       if (Action != SK_PNMI_GET) {
+
+               *pLen = 0;
+               return (SK_PNMI_ERR_READ_ONLY);
+       }
+
+       /*
+        * Check if the buffer length is large enough.
+        */
+       switch (Id) {
+
+       case OID_SKGE_RLMT_PORT_INDEX:
+       case OID_SKGE_RLMT_STATUS:
+               if (*pLen < (Limit - PhysPortIndex) * sizeof(SK_U32)) {
+
+                       *pLen = (Limit - PhysPortIndex) * sizeof(SK_U32);
+                       return (SK_PNMI_ERR_TOO_SHORT);
+               }
+               break;
+
+       case OID_SKGE_RLMT_TX_HELLO_CTS:
+       case OID_SKGE_RLMT_RX_HELLO_CTS:
+       case OID_SKGE_RLMT_TX_SP_REQ_CTS:
+       case OID_SKGE_RLMT_RX_SP_CTS:
+               if (*pLen < (Limit - PhysPortIndex) * sizeof(SK_U64)) {
+
+                       *pLen = (Limit - PhysPortIndex) * sizeof(SK_U64);
+                       return (SK_PNMI_ERR_TOO_SHORT);
+               }
+               break;
+
+       default:
+               SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR039,
+                       SK_PNMI_ERR039MSG);
+
+               *pLen = 0;
+               return (SK_PNMI_ERR_GENERAL);
+
+       }
+
+       /*
+        * Update statistic and increment semaphores to indicate that
+        * an update was already done.
+        */
+       if ((Ret = RlmtUpdate(pAC, IoC, NetIndex)) != SK_PNMI_ERR_OK) {
+
+               *pLen = 0;
+               return (Ret);
+       }
+       pAC->Pnmi.RlmtUpdatedFlag ++;
+
+       /*
+        * Get value
+        */
+       Offset = 0;
+       for (; PhysPortIndex < Limit; PhysPortIndex ++) {
+
+               switch (Id) {
+
+               case OID_SKGE_RLMT_PORT_INDEX:
+                       Val32 = PhysPortIndex;
+                       SK_PNMI_STORE_U32(pBuf + Offset, Val32);
+                       Offset += sizeof(SK_U32);
+                       break;
+
+               case OID_SKGE_RLMT_STATUS:
+                       if (pAC->Rlmt.Port[PhysPortIndex].PortState ==
+                               SK_RLMT_PS_INIT ||
+                               pAC->Rlmt.Port[PhysPortIndex].PortState ==
+                               SK_RLMT_PS_DOWN) {
+
+                               Val32 = SK_PNMI_RLMT_STATUS_ERROR;
+                       }
+                       else if (pAC->Pnmi.Port[PhysPortIndex].ActiveFlag) {
+
+                               Val32 = SK_PNMI_RLMT_STATUS_ACTIVE;
+                       }
+                       else {
+                               Val32 = SK_PNMI_RLMT_STATUS_STANDBY;
+                       }
+                       SK_PNMI_STORE_U32(pBuf + Offset, Val32);
+                       Offset += sizeof(SK_U32);
+                       break;
+
+               case OID_SKGE_RLMT_TX_HELLO_CTS:
+                       Val64 = pAC->Rlmt.Port[PhysPortIndex].TxHelloCts;
+                       SK_PNMI_STORE_U64(pBuf + Offset, Val64);
+                       Offset += sizeof(SK_U64);
+                       break;
+
+               case OID_SKGE_RLMT_RX_HELLO_CTS:
+                       Val64 = pAC->Rlmt.Port[PhysPortIndex].RxHelloCts;
+                       SK_PNMI_STORE_U64(pBuf + Offset, Val64);
+                       Offset += sizeof(SK_U64);
+                       break;
+
+               case OID_SKGE_RLMT_TX_SP_REQ_CTS:
+                       Val64 = pAC->Rlmt.Port[PhysPortIndex].TxSpHelloReqCts;
+                       SK_PNMI_STORE_U64(pBuf + Offset, Val64);
+                       Offset += sizeof(SK_U64);
+                       break;
+
+               case OID_SKGE_RLMT_RX_SP_CTS:
+                       Val64 = pAC->Rlmt.Port[PhysPortIndex].RxSpHelloCts;
+                       SK_PNMI_STORE_U64(pBuf + Offset, Val64);
+                       Offset += sizeof(SK_U64);
+                       break;
+
+               default:
+                       SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_ERR,
+                               ("RlmtStat: Unknown OID should be errored before"));
+
+                       pAC->Pnmi.RlmtUpdatedFlag --;
+                       *pLen = 0;
+                       return (SK_PNMI_ERR_GENERAL);
+               }
+       }
+       *pLen = Offset;
+
+       pAC->Pnmi.RlmtUpdatedFlag --;
+
+       return (SK_PNMI_ERR_OK);
+}
+
+/*****************************************************************************
+ *
+ * MacPrivateConf - OID handler function of OIDs concerning the configuration
+ *
+ * Description:
+ *     Get/Presets/Sets the OIDs concerning the configuration.
+ *
+ * Returns:
+ *     SK_PNMI_ERR_OK           The request was successfully performed.
+ *     SK_PNMI_ERR_GENERAL      A general severe internal error occured.
+ *     SK_PNMI_ERR_TOO_SHORT    The passed buffer is too short to contain
+ *                              the correct data (e.g. a 32bit value is
+ *                              needed, but a 16 bit value was passed).
+ *     SK_PNMI_ERR_BAD_VALUE    The passed value is not in the valid
+ *                              value range.
+ *     SK_PNMI_ERR_READ_ONLY    The OID is read-only and cannot be set.
+ *     SK_PNMI_ERR_UNKNOWN_INST The requested instance of the OID doesn't
+ *                           exist (e.g. port instance 3 on a two port
+ *                              adapter.
+ */
+PNMI_STATIC int MacPrivateConf(
+SK_AC *pAC,            /* Pointer to adapter context */
+SK_IOC IoC,            /* IO context handle */
+int Action,            /* GET/PRESET/SET action */
+SK_U32 Id,             /* Object ID that is to be processed */
+char *pBuf,            /* Buffer used for the management data transfer */
+unsigned int *pLen,    /* On call: pBuf buffer length. On return: used buffer */
+SK_U32 Instance,       /* Instance (1..n) that is to be queried or -1 */
+unsigned int TableIndex, /* Index to the Id table */
+SK_U32 NetIndex)       /* NetIndex (0..n), in single net mode always zero */
+{
+       unsigned int    PhysPortMax;
+       unsigned int    PhysPortIndex;
+       unsigned int    LogPortMax;
+       unsigned int    LogPortIndex;
+       unsigned int    Limit;
+       unsigned int    Offset;
+       char            Val8;
+       char            *pBufPtr;
+       int                     Ret;
+       SK_EVPARA       EventParam;
+       SK_U32          Val32;
+
+       /*
+        * Calculate instance if wished. MAC index 0 is the virtual MAC.
+        */
+       PhysPortMax = pAC->GIni.GIMacsFound;
+       LogPortMax = SK_PNMI_PORT_PHYS2LOG(PhysPortMax);
+
+       if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) { /* Dual net mode */
+               LogPortMax--;
+       }
+
+       if ((Instance != (SK_U32)(-1))) { /* Only one specific instance is queried */
+               /* Check instance range */
+               if ((Instance < 1) || (Instance > LogPortMax)) {
+
+                       *pLen = 0;
+                       return (SK_PNMI_ERR_UNKNOWN_INST);
+               }
+               LogPortIndex = SK_PNMI_PORT_INST2LOG(Instance);
+               Limit = LogPortIndex + 1;
+       }
+
+       else { /* Instance == (SK_U32)(-1), get all Instances of that OID */
+
+               LogPortIndex = 0;
+               Limit = LogPortMax;
+       }
+
+       /*
+        * Perform action
+        */
+       if (Action == SK_PNMI_GET) {
+
+               /* Check length */
+               switch (Id) {
+
+               case OID_SKGE_PMD:
+               case OID_SKGE_CONNECTOR:
+               case OID_SKGE_LINK_CAP:
+               case OID_SKGE_LINK_MODE:
+               case OID_SKGE_LINK_MODE_STATUS:
+               case OID_SKGE_LINK_STATUS:
+               case OID_SKGE_FLOWCTRL_CAP:
+               case OID_SKGE_FLOWCTRL_MODE:
+               case OID_SKGE_FLOWCTRL_STATUS:
+               case OID_SKGE_PHY_OPERATION_CAP:
+               case OID_SKGE_PHY_OPERATION_MODE:
+               case OID_SKGE_PHY_OPERATION_STATUS:
+               case OID_SKGE_SPEED_CAP:
+               case OID_SKGE_SPEED_MODE:
+               case OID_SKGE_SPEED_STATUS:
+                       if (*pLen < (Limit - LogPortIndex) * sizeof(SK_U8)) {
+
+                               *pLen = (Limit - LogPortIndex) * sizeof(SK_U8);
+                               return (SK_PNMI_ERR_TOO_SHORT);
+                       }
+                       break;
+
+        case OID_SKGE_MTU:
+        case OID_SKGE_PHY_TYPE:
+                       if (*pLen < (Limit - LogPortIndex) * sizeof(SK_U32)) {
+
+                               *pLen = (Limit - LogPortIndex) * sizeof(SK_U32);
+                               return (SK_PNMI_ERR_TOO_SHORT);
+                       }
+                       break;
+
+               default:
+                       SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR041,
+                               SK_PNMI_ERR041MSG);
+                       *pLen = 0;
+                       return (SK_PNMI_ERR_GENERAL);
+               }
+
+               /*
+                * Update statistic and increment semaphore to indicate
+                * that an update was already done.
+                */
+               if ((Ret = SirqUpdate(pAC, IoC)) != SK_PNMI_ERR_OK) {
+
+                       *pLen = 0;
+                       return (Ret);
+               }
+               pAC->Pnmi.SirqUpdatedFlag ++;
+
+               /*
+                * Get value
+                */
+               Offset = 0;
+               for (; LogPortIndex < Limit; LogPortIndex ++) {
+
+                       pBufPtr = pBuf + Offset;
+                       
+                       switch (Id) {
+
+                       case OID_SKGE_PMD:
+                               *pBufPtr = pAC->Pnmi.PMD;
+                               Offset += sizeof(char);
+                               break;
+
+                       case OID_SKGE_CONNECTOR:
+                               *pBufPtr = pAC->Pnmi.Connector;
+                               Offset += sizeof(char);
+                               break;
+
+                       case OID_SKGE_PHY_TYPE:
+                               if (!pAC->Pnmi.DualNetActiveFlag) { /* SingleNetMode */
+                                       if (LogPortIndex == 0) {
+                                               continue;
+                                       }
+                                       else {
+                                               /* Get value for physical ports */
+                                               PhysPortIndex = SK_PNMI_PORT_LOG2PHYS(
+                                                       pAC, LogPortIndex);
+                                               Val32 = pAC->GIni.GP[PhysPortIndex].PhyType;
+                                               SK_PNMI_STORE_U32(pBufPtr, Val32);
+                                       }
+                               }
+                               else { /* DualNetMode */
+                                       
+                                       Val32 = pAC->GIni.GP[NetIndex].PhyType;
+                                       SK_PNMI_STORE_U32(pBufPtr, Val32);
+                               }
+                               Offset += sizeof(SK_U32);
+                               break;
+
+                       case OID_SKGE_LINK_CAP:
+                               if (!pAC->Pnmi.DualNetActiveFlag) { /* SingleNetMode */
+                                       if (LogPortIndex == 0) {
+                                               /* Get value for virtual port */
+                                               VirtualConf(pAC, IoC, Id, pBufPtr);
+                                       }
+                                       else {
+                                               /* Get value for physical ports */
+                                               PhysPortIndex = SK_PNMI_PORT_LOG2PHYS(
+                                                       pAC, LogPortIndex);
+
+                                               *pBufPtr = pAC->GIni.GP[PhysPortIndex].PLinkCap;
+                                       }
+                               }
+                               else { /* DualNetMode */
+                                       
+                                       *pBufPtr = pAC->GIni.GP[NetIndex].PLinkCap;
+                               }
+                               Offset += sizeof(char);
+                               break;
+
+                       case OID_SKGE_LINK_MODE:
+                               if (!pAC->Pnmi.DualNetActiveFlag) { /* SingleNetMode */
+                                       if (LogPortIndex == 0) {
+                                               /* Get value for virtual port */
+                                               VirtualConf(pAC, IoC, Id, pBufPtr);
+                                       }
+                                       else {
+                                               /* Get value for physical ports */
+                                               PhysPortIndex = SK_PNMI_PORT_LOG2PHYS(
+                                                       pAC, LogPortIndex);
+
+                                               *pBufPtr = pAC->GIni.GP[PhysPortIndex].PLinkModeConf;
+                                       }
+                               }
+                               else { /* DualNetMode */
+                               
+                                       *pBufPtr = pAC->GIni.GP[NetIndex].PLinkModeConf;
+                               }
+                               Offset += sizeof(char);
+                               break;
+
+                       case OID_SKGE_LINK_MODE_STATUS:
+                               if (!pAC->Pnmi.DualNetActiveFlag) { /* SingleNetMode */
+                                       if (LogPortIndex == 0) {
+                                               /* Get value for virtual port */
+                                               VirtualConf(pAC, IoC, Id, pBufPtr);
+                                       }
+                                       else {
+                                               /* Get value for physical port */
+                                               PhysPortIndex = SK_PNMI_PORT_LOG2PHYS(
+                                                       pAC, LogPortIndex);
+
+                                               *pBufPtr =
+                                                       CalculateLinkModeStatus(pAC, IoC, PhysPortIndex);
+                                       }
+                               }
+                               else { /* DualNetMode */
+                                       
+                                       *pBufPtr = CalculateLinkModeStatus(pAC, IoC, NetIndex);
+                               }
+                               Offset += sizeof(char);
+                               break;
+
+                       case OID_SKGE_LINK_STATUS:
+                               if (!pAC->Pnmi.DualNetActiveFlag) { /* SingleNetMode */
+                                       if (LogPortIndex == 0) {
+                                               /* Get value for virtual port */
+                                               VirtualConf(pAC, IoC, Id, pBufPtr);
+                                       }
+                                       else {
+                                               /* Get value for physical ports */
+                                               PhysPortIndex = SK_PNMI_PORT_LOG2PHYS(
+                                                       pAC, LogPortIndex);
+       
+                                               *pBufPtr = CalculateLinkStatus(pAC, IoC, PhysPortIndex);
+                                       }
+                               }
+                               else { /* DualNetMode */
+
+                                       *pBufPtr = CalculateLinkStatus(pAC, IoC, NetIndex);
+                               }
+                               Offset += sizeof(char);
+                               break;
+
+                       case OID_SKGE_FLOWCTRL_CAP:
+                               if (!pAC->Pnmi.DualNetActiveFlag) { /* SingleNetMode */
+                                       if (LogPortIndex == 0) {
+                                               /* Get value for virtual port */
+                                               VirtualConf(pAC, IoC, Id, pBufPtr);
+                                       }
+                                       else {
+                                               /* Get value for physical ports */
+                                               PhysPortIndex = SK_PNMI_PORT_LOG2PHYS(
+                                                       pAC, LogPortIndex);
+       
+                                               *pBufPtr = pAC->GIni.GP[PhysPortIndex].PFlowCtrlCap;
+                                       }
+                               }
+                               else { /* DualNetMode */
+                               
+                                       *pBufPtr = pAC->GIni.GP[NetIndex].PFlowCtrlCap;
+                               }
+                               Offset += sizeof(char);
+                               break;
+
+                       case OID_SKGE_FLOWCTRL_MODE:
+                               if (!pAC->Pnmi.DualNetActiveFlag) { /* SingleNetMode */
+                                       if (LogPortIndex == 0) {
+                                               /* Get value for virtual port */
+                                               VirtualConf(pAC, IoC, Id, pBufPtr);
+                                       }
+                                       else {
+                                               /* Get value for physical port */
+                                               PhysPortIndex = SK_PNMI_PORT_LOG2PHYS(
+                                                       pAC, LogPortIndex);
+       
+                                               *pBufPtr = pAC->GIni.GP[PhysPortIndex].PFlowCtrlMode;
+                                       }
+                               }
+                               else { /* DualNetMode */
+
+                                       *pBufPtr = pAC->GIni.GP[NetIndex].PFlowCtrlMode;
+                               }
+                               Offset += sizeof(char);
+                               break;
+
+                       case OID_SKGE_FLOWCTRL_STATUS:
+                               if (!pAC->Pnmi.DualNetActiveFlag) { /* SingleNetMode */
+                                       if (LogPortIndex == 0) {
+                                               /* Get value for virtual port */
+                                               VirtualConf(pAC, IoC, Id, pBufPtr);
+                                       }
+                                       else {
+                                               /* Get value for physical port */
+                                               PhysPortIndex = SK_PNMI_PORT_LOG2PHYS(
+                                                       pAC, LogPortIndex);
+       
+                                               *pBufPtr = pAC->GIni.GP[PhysPortIndex].PFlowCtrlStatus;
+                                       }
+                               }
+                               else { /* DualNetMode */
+
+                                       *pBufPtr = pAC->GIni.GP[NetIndex].PFlowCtrlStatus;
+                               }
+                               Offset += sizeof(char);
+                               break;
+
+                       case OID_SKGE_PHY_OPERATION_CAP:
+                               if (!pAC->Pnmi.DualNetActiveFlag) { /* SingleNetMode */
+                                       if (LogPortIndex == 0) {
+                                               /* Get value for virtual port */
+                                               VirtualConf(pAC, IoC, Id, pBufPtr);
+                                       }
+                                       else {
+                                               /* Get value for physical ports */
+                                               PhysPortIndex = SK_PNMI_PORT_LOG2PHYS(
+                                                       pAC, LogPortIndex);
+       
+                                               *pBufPtr = pAC->GIni.GP[PhysPortIndex].PMSCap;
+                                       }
+                               }
+                               else { /* DualNetMode */
+                               
+                                       *pBufPtr = pAC->GIni.GP[NetIndex].PMSCap;
+                               }
+                               Offset += sizeof(char);
+                               break;
+
+                       case OID_SKGE_PHY_OPERATION_MODE:
+                               if (!pAC->Pnmi.DualNetActiveFlag) { /* SingleNetMode */
+                                       if (LogPortIndex == 0) {
+                                               /* Get value for virtual port */
+                                               VirtualConf(pAC, IoC, Id, pBufPtr);
+                                       }
+                                       else {
+                                               /* Get value for physical port */
+                                               PhysPortIndex = SK_PNMI_PORT_LOG2PHYS(
+                                                       pAC, LogPortIndex);
+
+                                               *pBufPtr = pAC->GIni.GP[PhysPortIndex].PMSMode;
+                                       }
+                               }
+                               else { /* DualNetMode */
+                               
+                                       *pBufPtr = pAC->GIni.GP[NetIndex].PMSMode;
+                               }
+                               Offset += sizeof(char);
+                               break;
+
+                       case OID_SKGE_PHY_OPERATION_STATUS:
+                               if (!pAC->Pnmi.DualNetActiveFlag) { /* SingleNetMode */
+                                       if (LogPortIndex == 0) {
+                                               /* Get value for virtual port */
+                                               VirtualConf(pAC, IoC, Id, pBufPtr);
+                                       }
+                                       else {
+                                               /* Get value for physical port */
+                                               PhysPortIndex = SK_PNMI_PORT_LOG2PHYS(
+                                                       pAC, LogPortIndex);
+       
+                                               *pBufPtr = pAC->GIni.GP[PhysPortIndex].PMSStatus;
+                                       }
+                               }
+                               else {
+                               
+                                       *pBufPtr = pAC->GIni.GP[NetIndex].PMSStatus;
+                               }
+                               Offset += sizeof(char);
+                               break;
+
+                       case OID_SKGE_SPEED_CAP:
+                               if (!pAC->Pnmi.DualNetActiveFlag) { /* SingleNetMode */
+                                       if (LogPortIndex == 0) {
+                                               /* Get value for virtual port */
+                                               VirtualConf(pAC, IoC, Id, pBufPtr);
+                                       }
+                                       else {
+                                               /* Get value for physical ports */
+                                               PhysPortIndex = SK_PNMI_PORT_LOG2PHYS(
+                                                       pAC, LogPortIndex);
+       
+                                               *pBufPtr = pAC->GIni.GP[PhysPortIndex].PLinkSpeedCap;
+                                       }
+                               }
+                               else { /* DualNetMode */
+                               
+                                       *pBufPtr = pAC->GIni.GP[NetIndex].PLinkSpeedCap;
+                               }
+                               Offset += sizeof(char);
+                               break;
+
+                       case OID_SKGE_SPEED_MODE:
+                               if (!pAC->Pnmi.DualNetActiveFlag) { /* SingleNetMode */
+                                       if (LogPortIndex == 0) {
+                                               /* Get value for virtual port */
+                                               VirtualConf(pAC, IoC, Id, pBufPtr);
+                                       }
+                                       else {
+                                               /* Get value for physical port */
+                                               PhysPortIndex = SK_PNMI_PORT_LOG2PHYS(
+                                                       pAC, LogPortIndex);
+       
+                                               *pBufPtr = pAC->GIni.GP[PhysPortIndex].PLinkSpeed;
+                                       }
+                               }
+                               else { /* DualNetMode */
+
+                                       *pBufPtr = pAC->GIni.GP[NetIndex].PLinkSpeed;
+                               }
+                               Offset += sizeof(char);
+                               break;
+
+                       case OID_SKGE_SPEED_STATUS:
+                               if (!pAC->Pnmi.DualNetActiveFlag) { /* SingleNetMode */
+                                       if (LogPortIndex == 0) {
+                                               /* Get value for virtual port */
+                                               VirtualConf(pAC, IoC, Id, pBufPtr);
+                                       }
+                                       else {
+                                               /* Get value for physical port */
+                                               PhysPortIndex = SK_PNMI_PORT_LOG2PHYS(
+                                                       pAC, LogPortIndex);
+       
+                                               *pBufPtr = pAC->GIni.GP[PhysPortIndex].PLinkSpeedUsed;
+                                       }
+                               }
+                               else { /* DualNetMode */
+
+                                       *pBufPtr = pAC->GIni.GP[NetIndex].PLinkSpeedUsed;
+                               }
+                               Offset += sizeof(char);
+                               break;
+                       
+                       case OID_SKGE_MTU:
+                               Val32 = SK_DRIVER_GET_MTU(pAC, IoC, NetIndex);
+                               SK_PNMI_STORE_U32(pBufPtr, Val32);
+                               Offset += sizeof(SK_U32);
+                               break;
+
+                       default:
+                               SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_ERR,
+                                       ("MacPrivateConf: Unknown OID should be handled before"));
+
+                               pAC->Pnmi.SirqUpdatedFlag --;
+                               return (SK_PNMI_ERR_GENERAL);
+                       }
+               }
+               *pLen = Offset;
+               pAC->Pnmi.SirqUpdatedFlag --;
+
+               return (SK_PNMI_ERR_OK);
+       }
+
+       /*
+        * From here SET or PRESET action. Check if the passed
+        * buffer length is plausible.
+        */
+       switch (Id) {
+
+       case OID_SKGE_LINK_MODE:
+       case OID_SKGE_FLOWCTRL_MODE:
+       case OID_SKGE_PHY_OPERATION_MODE:
+       case OID_SKGE_SPEED_MODE:
+               if (*pLen < Limit - LogPortIndex) {
+
+                       *pLen = Limit - LogPortIndex;
+                       return (SK_PNMI_ERR_TOO_SHORT);
+               }
+               if (*pLen != Limit - LogPortIndex) {
+
+                       *pLen = 0;
+                       return (SK_PNMI_ERR_BAD_VALUE);
+               }
+               break;
+
+       case OID_SKGE_MTU:
+               if (*pLen < sizeof(SK_U32)) {
+
+                       *pLen = sizeof(SK_U32);
+                       return (SK_PNMI_ERR_TOO_SHORT);
+               }
+               if (*pLen != sizeof(SK_U32)) {
+
+                       *pLen = 0;
+                       return (SK_PNMI_ERR_BAD_VALUE);
+               }
+               break;
+
+    default:
+               *pLen = 0;
+               return (SK_PNMI_ERR_READ_ONLY);
+       }
+
+       /*
+        * Perform preset or set
+        */
+       Offset = 0;
+       for (; LogPortIndex < Limit; LogPortIndex ++) {
+
+               switch (Id) {
+
+               case OID_SKGE_LINK_MODE:
+                       /* Check the value range */
+                       Val8 = *(pBuf + Offset);
+                       if (Val8 == 0) {
+
+                               Offset += sizeof(char);
+                               break;
+                       }
+                       if (Val8 < SK_LMODE_HALF ||
+                               (LogPortIndex != 0 && Val8 > SK_LMODE_AUTOSENSE) ||
+                               (LogPortIndex == 0 && Val8 > SK_LMODE_INDETERMINATED)) {
+
+                               *pLen = 0;
+                               return (SK_PNMI_ERR_BAD_VALUE);
+                       }
+
+                       /* The preset ends here */
+                       if (Action == SK_PNMI_PRESET) {
+
+                               return (SK_PNMI_ERR_OK);
+                       }
+
+                       if (LogPortIndex == 0) {
+
+                               /*
+                                * The virtual port consists of all currently
+                                * active ports. Find them and send an event
+                                * with the new link mode to SIRQ.
+                                */
+                               for (PhysPortIndex = 0;
+                                       PhysPortIndex < PhysPortMax;
+                                       PhysPortIndex ++) {
+
+                                       if (!pAC->Pnmi.Port[PhysPortIndex].
+                                               ActiveFlag) {
+
+                                               continue;
+                                       }
+
+                                       EventParam.Para32[0] = PhysPortIndex;
+                                       EventParam.Para32[1] = (SK_U32)Val8;
+                                       if (SkGeSirqEvent(pAC, IoC,
+                                               SK_HWEV_SET_LMODE,
+                                               EventParam) > 0) {
+
+                                               SK_ERR_LOG(pAC, SK_ERRCL_SW,
+                                                       SK_PNMI_ERR043,
+                                                       SK_PNMI_ERR043MSG);
+
+                                               *pLen = 0;
+                                               return (SK_PNMI_ERR_GENERAL);
+                                       }
+                               }
+                       }
+                       else {
+                               /*
+                                * Send an event with the new link mode to
+                                * the SIRQ module.
+                                */
+                               EventParam.Para32[0] = SK_PNMI_PORT_LOG2PHYS(
+                                       pAC, LogPortIndex);
+                               EventParam.Para32[1] = (SK_U32)Val8;
+                               if (SkGeSirqEvent(pAC, IoC, SK_HWEV_SET_LMODE,
+                                       EventParam) > 0) {
+
+                                       SK_ERR_LOG(pAC, SK_ERRCL_SW,
+                                               SK_PNMI_ERR043,
+                                               SK_PNMI_ERR043MSG);
+
+                                       *pLen = 0;
+                                       return (SK_PNMI_ERR_GENERAL);
+                               }
+                       }
+                       Offset += sizeof(char);
+                       break;
+
+               case OID_SKGE_FLOWCTRL_MODE:
+                       /* Check the value range */
+                       Val8 = *(pBuf + Offset);
+                       if (Val8 == 0) {
+
+                               Offset += sizeof(char);
+                               break;
+                       }
+                       if (Val8 < SK_FLOW_MODE_NONE ||
+                               (LogPortIndex != 0 && Val8 > SK_FLOW_MODE_SYM_OR_REM) ||
+                               (LogPortIndex == 0 && Val8 > SK_FLOW_MODE_INDETERMINATED)) {
+
+                               *pLen = 0;
+                               return (SK_PNMI_ERR_BAD_VALUE);
+                       }
+
+                       /* The preset ends here */
+                       if (Action == SK_PNMI_PRESET) {
+
+                               return (SK_PNMI_ERR_OK);
+                       }
+
+                       if (LogPortIndex == 0) {
+
+                               /*
+                                * The virtual port consists of all currently
+                                * active ports. Find them and send an event
+                                * with the new flow control mode to SIRQ.
+                                */
+                               for (PhysPortIndex = 0;
+                                       PhysPortIndex < PhysPortMax;
+                                       PhysPortIndex ++) {
+
+                                       if (!pAC->Pnmi.Port[PhysPortIndex].
+                                               ActiveFlag) {
+
+                                               continue;
+                                       }
+
+                                       EventParam.Para32[0] = PhysPortIndex;
+                                       EventParam.Para32[1] = (SK_U32)Val8;
+                                       if (SkGeSirqEvent(pAC, IoC,
+                                               SK_HWEV_SET_FLOWMODE,
+                                               EventParam) > 0) {
+
+                                               SK_ERR_LOG(pAC, SK_ERRCL_SW,
+                                                       SK_PNMI_ERR044,
+                                                       SK_PNMI_ERR044MSG);
+
+                                               *pLen = 0;
+                                               return (SK_PNMI_ERR_GENERAL);
+                                       }
+                               }
+                       }
+                       else {
+                               /*
+                                * Send an event with the new flow control
+                                * mode to the SIRQ module.
+                                */
+                               EventParam.Para32[0] = SK_PNMI_PORT_LOG2PHYS(
+                                       pAC, LogPortIndex);
+                               EventParam.Para32[1] = (SK_U32)Val8;
+                               if (SkGeSirqEvent(pAC, IoC,
+                                       SK_HWEV_SET_FLOWMODE, EventParam)
+                                       > 0) {
+
+                                       SK_ERR_LOG(pAC, SK_ERRCL_SW,
+                                               SK_PNMI_ERR044,
+                                               SK_PNMI_ERR044MSG);
+
+                                       *pLen = 0;
+                                       return (SK_PNMI_ERR_GENERAL);
+                               }
+                       }
+                       Offset += sizeof(char);
+                       break;
+
+               case OID_SKGE_PHY_OPERATION_MODE :
+                       /* Check the value range */
+                       Val8 = *(pBuf + Offset);
+                       if (Val8 == 0) {
+                               /* mode of this port remains unchanged */
+                               Offset += sizeof(char);
+                               break;
+                       }
+                       if (Val8 < SK_MS_MODE_AUTO ||
+                               (LogPortIndex != 0 && Val8 > SK_MS_MODE_SLAVE) ||
+                               (LogPortIndex == 0 && Val8 > SK_MS_MODE_INDETERMINATED)) {
+
+                               *pLen = 0;
+                               return (SK_PNMI_ERR_BAD_VALUE);
+                       }
+
+                       /* The preset ends here */
+                       if (Action == SK_PNMI_PRESET) {
+
+                               return (SK_PNMI_ERR_OK);
+                       }
+
+                       if (LogPortIndex == 0) {
+
+                               /*
+                                * The virtual port consists of all currently
+                                * active ports. Find them and send an event
+                                * with new master/slave (role) mode to SIRQ.
+                                */
+                               for (PhysPortIndex = 0;
+                                       PhysPortIndex < PhysPortMax;
+                                       PhysPortIndex ++) {
+
+                                       if (!pAC->Pnmi.Port[PhysPortIndex].
+                                               ActiveFlag) {
+
+                                               continue;
+                                       }
+
+                                       EventParam.Para32[0] = PhysPortIndex;
+                                       EventParam.Para32[1] = (SK_U32)Val8;
+                                       if (SkGeSirqEvent(pAC, IoC,
+                                               SK_HWEV_SET_ROLE,
+                                               EventParam) > 0) {
+
+                                               SK_ERR_LOG(pAC, SK_ERRCL_SW,
+                                                       SK_PNMI_ERR042,
+                                                       SK_PNMI_ERR042MSG);
+
+                                               *pLen = 0;
+                                               return (SK_PNMI_ERR_GENERAL);
+                                       }
+                               }
+                       }
+                       else {
+                               /*
+                                * Send an event with the new master/slave
+                                * (role) mode to the SIRQ module.
+                                */
+                               EventParam.Para32[0] = SK_PNMI_PORT_LOG2PHYS(
+                                       pAC, LogPortIndex);
+                               EventParam.Para32[1] = (SK_U32)Val8;
+                               if (SkGeSirqEvent(pAC, IoC,
+                                       SK_HWEV_SET_ROLE, EventParam) > 0) {
+
+                                       SK_ERR_LOG(pAC, SK_ERRCL_SW,
+                                               SK_PNMI_ERR042,
+                                               SK_PNMI_ERR042MSG);
+
+                                       *pLen = 0;
+                                       return (SK_PNMI_ERR_GENERAL);
+                               }
+                       }
+
+                       Offset += sizeof(char);
+                       break;
+
+               case OID_SKGE_SPEED_MODE:
+                       /* Check the value range */
+                       Val8 = *(pBuf + Offset);
+                       if (Val8 == 0) {
+
+                               Offset += sizeof(char);
+                               break;
+                       }
+                       if (Val8 < (SK_LSPEED_AUTO) ||
+                               (LogPortIndex != 0 && Val8 > (SK_LSPEED_1000MBPS)) ||
+                               (LogPortIndex == 0 && Val8 > (SK_LSPEED_INDETERMINATED))) {
+
+                               *pLen = 0;
+                               return (SK_PNMI_ERR_BAD_VALUE);
+                       }
+
+                       /* The preset ends here */
+                       if (Action == SK_PNMI_PRESET) {
+
+                               return (SK_PNMI_ERR_OK);
+                       }
+
+                       if (LogPortIndex == 0) {
+
+                               /*
+                                * The virtual port consists of all currently
+                                * active ports. Find them and send an event
+                                * with the new flow control mode to SIRQ.
+                                */
+                               for (PhysPortIndex = 0;
+                                       PhysPortIndex < PhysPortMax;
+                                       PhysPortIndex ++) {
+
+                                       if (!pAC->Pnmi.Port[PhysPortIndex].ActiveFlag) {
+
+                                               continue;
+                                       }
+
+                                       EventParam.Para32[0] = PhysPortIndex;
+                                       EventParam.Para32[1] = (SK_U32)Val8;
+                                       if (SkGeSirqEvent(pAC, IoC,
+                                               SK_HWEV_SET_SPEED,
+                                               EventParam) > 0) {
+
+                                               SK_ERR_LOG(pAC, SK_ERRCL_SW,
+                                                       SK_PNMI_ERR045,
+                                                       SK_PNMI_ERR045MSG);
+
+                                               *pLen = 0;
+                                               return (SK_PNMI_ERR_GENERAL);
+                                       }
+                               }
+                       }
+                       else {
+                               /*
+                                * Send an event with the new flow control
+                                * mode to the SIRQ module.
+                                */
+                               EventParam.Para32[0] = SK_PNMI_PORT_LOG2PHYS(
+                                       pAC, LogPortIndex);
+                               EventParam.Para32[1] = (SK_U32)Val8;
+                               if (SkGeSirqEvent(pAC, IoC,
+                                       SK_HWEV_SET_SPEED,
+                                       EventParam) > 0) {
+
+                                       SK_ERR_LOG(pAC, SK_ERRCL_SW,
+                                               SK_PNMI_ERR045,
+                                               SK_PNMI_ERR045MSG);
+
+                                       *pLen = 0;
+                                       return (SK_PNMI_ERR_GENERAL);
+                               }
+                       }
+                       Offset += sizeof(char);
+                       break;
+
+               case OID_SKGE_MTU :
+                       /* Check the value range */
+                       Val32 = *(SK_U32*)(pBuf + Offset);
+                       if (Val32 == 0) {
+                               /* mtu of this port remains unchanged */
+                               Offset += sizeof(SK_U32);
+                               break;
+                       }
+                       if (SK_DRIVER_PRESET_MTU(pAC, IoC, NetIndex, Val32) != 0) {
+                               *pLen = 0;
+                               return (SK_PNMI_ERR_BAD_VALUE);
+                       }
+
+                       /* The preset ends here */
+                       if (Action == SK_PNMI_PRESET) {
+                               return (SK_PNMI_ERR_OK);
+                       }
+
+                       if (SK_DRIVER_SET_MTU(pAC, IoC, NetIndex, Val32) != 0) {
+                               return (SK_PNMI_ERR_GENERAL);
+                       }
+
+                       Offset += sizeof(SK_U32);
+                       break;
+               
+               default:
+            SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_ERR,
+                ("MacPrivateConf: Unknown OID should be handled before set"));
+
+                       *pLen = 0;
+                       return (SK_PNMI_ERR_GENERAL);
+               }
+       }
+
+       return (SK_PNMI_ERR_OK);
+}
+
+/*****************************************************************************
+ *
+ * Monitor - OID handler function for RLMT_MONITOR_XXX
+ *
+ * Description:
+ *     Because RLMT currently does not support the monitoring of
+ *     remote adapter cards, we return always an empty table.
+ *
+ * Returns:
+ *     SK_PNMI_ERR_OK           The request was successfully performed.
+ *     SK_PNMI_ERR_GENERAL      A general severe internal error occured.
+ *     SK_PNMI_ERR_TOO_SHORT    The passed buffer is too short to contain
+ *                              the correct data (e.g. a 32bit value is
+ *                              needed, but a 16 bit value was passed).
+ *     SK_PNMI_ERR_BAD_VALUE    The passed value is not in the valid
+ *                              value range.
+ *     SK_PNMI_ERR_READ_ONLY    The OID is read-only and cannot be set.
+ *     SK_PNMI_ERR_UNKNOWN_INST The requested instance of the OID doesn't
+ *                           exist (e.g. port instance 3 on a two port
+ *                              adapter.
+ */
+PNMI_STATIC int Monitor(
+SK_AC *pAC,            /* Pointer to adapter context */
+SK_IOC IoC,            /* IO context handle */
+int Action,            /* GET/PRESET/SET action */
+SK_U32 Id,             /* Object ID that is to be processed */
+char *pBuf,            /* Buffer used for the management data transfer */
+unsigned int *pLen,    /* On call: pBuf buffer length. On return: used buffer */
+SK_U32 Instance,       /* Instance (1..n) that is to be queried or -1 */
+unsigned int TableIndex, /* Index to the Id table */
+SK_U32 NetIndex)       /* NetIndex (0..n), in single net mode always zero */
+{
+       unsigned int    Index;
+       unsigned int    Limit;
+       unsigned int    Offset;
+       unsigned int    Entries;
+
+       
+       /*
+        * Calculate instance if wished.
+        */
+       /* XXX Not yet implemented. Return always an empty table. */
+       Entries = 0;
+
+       if ((Instance != (SK_U32)(-1))) {
+
+               if ((Instance < 1) || (Instance > Entries)) {
+
+                       *pLen = 0;
+                       return (SK_PNMI_ERR_UNKNOWN_INST);
+               }
+
+               Index = (unsigned int)Instance - 1;
+               Limit = (unsigned int)Instance;
+       }
+       else {
+               Index = 0;
+               Limit = Entries;
+       }
+
+       /*
+        * Get/Set value
+       */
+       if (Action == SK_PNMI_GET) {
+
+               for (Offset=0; Index < Limit; Index ++) {
+
+                       switch (Id) {
+
+                       case OID_SKGE_RLMT_MONITOR_INDEX:
+                       case OID_SKGE_RLMT_MONITOR_ADDR:
+                       case OID_SKGE_RLMT_MONITOR_ERRS:
+                       case OID_SKGE_RLMT_MONITOR_TIMESTAMP:
+                       case OID_SKGE_RLMT_MONITOR_ADMIN:
+                               break;
+
+                       default:
+                               SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR046,
+                                       SK_PNMI_ERR046MSG);
+
+                               *pLen = 0;
+                               return (SK_PNMI_ERR_GENERAL);
+                       }
+               }
+               *pLen = Offset;
+       }
+       else {
+               /* Only MONITOR_ADMIN can be set */
+               if (Id != OID_SKGE_RLMT_MONITOR_ADMIN) {
+
+                       *pLen = 0;
+                       return (SK_PNMI_ERR_READ_ONLY);
+               }
+
+               /* Check if the length is plausible */
+               if (*pLen < (Limit - Index)) {
+
+                       return (SK_PNMI_ERR_TOO_SHORT);
+               }
+               /* Okay, we have a wide value range */
+               if (*pLen != (Limit - Index)) {
+
+                       *pLen = 0;
+                       return (SK_PNMI_ERR_BAD_VALUE);
+               }
+/*
+               for (Offset=0; Index < Limit; Index ++) {
+               }
+*/
+/*
+ * XXX Not yet implemented. Return always BAD_VALUE, because the table
+ * is empty.
+ */
+               *pLen = 0;
+               return (SK_PNMI_ERR_BAD_VALUE);
+       }
+
+       return (SK_PNMI_ERR_OK);
+}
+
+/*****************************************************************************
+ *
+ * VirtualConf - Calculates the values of configuration OIDs for virtual port
+ *
+ * Description:
+ *     We handle here the get of the configuration group OIDs, which are
+ *     a little bit complicated. The virtual port consists of all currently
+ *     active physical ports. If multiple ports are active and configured
+ *     differently we get in some trouble to return a single value. So we
+ *     get the value of the first active port and compare it with that of
+ *     the other active ports. If they are not the same, we return a value
+ *     that indicates that the state is indeterminated.
+ *
+ * Returns:
+ *     Nothing
+ */
+PNMI_STATIC void VirtualConf(
+SK_AC *pAC,            /* Pointer to adapter context */
+SK_IOC IoC,            /* IO context handle */
+SK_U32 Id,             /* Object ID that is to be processed */
+char *pBuf)            /* Buffer used for the management data transfer */
+{
+       unsigned int    PhysPortMax;
+       unsigned int    PhysPortIndex;
+       SK_U8           Val8;
+       SK_U32          Val32;
+       SK_BOOL         PortActiveFlag;
+       SK_GEPORT       *pPrt;
+
+       *pBuf = 0;
+       PortActiveFlag = SK_FALSE;
+       PhysPortMax = pAC->GIni.GIMacsFound;
+       
+       for (PhysPortIndex = 0; PhysPortIndex < PhysPortMax;
+               PhysPortIndex ++) {
+
+               pPrt = &pAC->GIni.GP[PhysPortIndex];
+
+               /* Check if the physical port is active */
+               if (!pAC->Pnmi.Port[PhysPortIndex].ActiveFlag) {
+
+                       continue;
+               }
+
+               PortActiveFlag = SK_TRUE;
+
+               switch (Id) {
+
+               case OID_SKGE_PHY_TYPE:
+                       /* Check if it is the first active port */
+                       if (*pBuf == 0) {
+                               Val32 = pPrt->PhyType;
+                               SK_PNMI_STORE_U32(pBuf, Val32);
+                               continue;
+                       }
+
+               case OID_SKGE_LINK_CAP:
+
+                       /*
+                        * Different capabilities should not happen, but
+                        * in the case of the cases OR them all together.
+                        * From a curious point of view the virtual port
+                        * is capable of all found capabilities.
+                        */
+                       *pBuf |= pPrt->PLinkCap;
+                       break;
+
+               case OID_SKGE_LINK_MODE:
+                       /* Check if it is the first active port */
+                       if (*pBuf == 0) {
+
+                               *pBuf = pPrt->PLinkModeConf;
+                               continue;
+                       }
+
+                       /*
+                        * If we find an active port with a different link
+                        * mode than the first one we return a value that
+                        * indicates that the link mode is indeterminated.
+                        */
+                       if (*pBuf != pPrt->PLinkModeConf) {
+
+                               *pBuf = SK_LMODE_INDETERMINATED;
+                       }
+                       break;
+
+               case OID_SKGE_LINK_MODE_STATUS:
+                       /* Get the link mode of the physical port */
+                       Val8 = CalculateLinkModeStatus(pAC, IoC, PhysPortIndex);
+
+                       /* Check if it is the first active port */
+                       if (*pBuf == 0) {
+
+                               *pBuf = Val8;
+                               continue;
+                       }
+
+                       /*
+                        * If we find an active port with a different link
+                        * mode status than the first one we return a value
+                        * that indicates that the link mode status is
+                        * indeterminated.
+                        */
+                       if (*pBuf != Val8) {
+
+                               *pBuf = SK_LMODE_STAT_INDETERMINATED;
+                       }
+                       break;
+
+               case OID_SKGE_LINK_STATUS:
+                       /* Get the link status of the physical port */
+                       Val8 = CalculateLinkStatus(pAC, IoC, PhysPortIndex);
+
+                       /* Check if it is the first active port */
+                       if (*pBuf == 0) {
+
+                               *pBuf = Val8;
+                               continue;
+                       }
+
+                       /*
+                        * If we find an active port with a different link
+                        * status than the first one, we return a value
+                        * that indicates that the link status is
+                        * indeterminated.
+                        */
+                       if (*pBuf != Val8) {
+
+                               *pBuf = SK_PNMI_RLMT_LSTAT_INDETERMINATED;
+                       }
+                       break;
+
+               case OID_SKGE_FLOWCTRL_CAP:
+                       /* Check if it is the first active port */
+                       if (*pBuf == 0) {
+
+                               *pBuf = pPrt->PFlowCtrlCap;
+                               continue;
+                       }
+
+                       /*
+                        * From a curious point of view the virtual port
+                        * is capable of all found capabilities.
+                        */
+                       *pBuf |= pPrt->PFlowCtrlCap;
+                       break;
+
+               case OID_SKGE_FLOWCTRL_MODE:
+                       /* Check if it is the first active port */
+                       if (*pBuf == 0) {
+
+                               *pBuf = pPrt->PFlowCtrlMode;
+                               continue;
+                       }
+
+                       /*
+                        * If we find an active port with a different flow
+                        * control mode than the first one, we return a value
+                        * that indicates that the mode is indeterminated.
+                        */
+                       if (*pBuf != pPrt->PFlowCtrlMode) {
+
+                               *pBuf = SK_FLOW_MODE_INDETERMINATED;
+                       }
+                       break;
+
+               case OID_SKGE_FLOWCTRL_STATUS:
+                       /* Check if it is the first active port */
+                       if (*pBuf == 0) {
+
+                               *pBuf = pPrt->PFlowCtrlStatus;
+                               continue;
+                       }
+
+                       /*
+                        * If we find an active port with a different flow
+                        * control status than the first one, we return a
+                        * value that indicates that the status is
+                        * indeterminated.
+                        */
+                       if (*pBuf != pPrt->PFlowCtrlStatus) {
+
+                               *pBuf = SK_FLOW_STAT_INDETERMINATED;
+                       }
+                       break;
+               
+               case OID_SKGE_PHY_OPERATION_CAP:
+                       /* Check if it is the first active port */
+                       if (*pBuf == 0) {
+
+                               *pBuf = pPrt->PMSCap;
+                               continue;
+                       }
+
+                       /*
+                        * From a curious point of view the virtual port
+                        * is capable of all found capabilities.
+                        */
+                       *pBuf |= pPrt->PMSCap;
+                       break;
+
+               case OID_SKGE_PHY_OPERATION_MODE:
+                       /* Check if it is the first active port */
+                       if (*pBuf == 0) {
+
+                               *pBuf = pPrt->PMSMode;
+                               continue;
+                       }
+
+                       /*
+                        * If we find an active port with a different master/
+                        * slave mode than the first one, we return a value
+                        * that indicates that the mode is indeterminated.
+                        */
+                       if (*pBuf != pPrt->PMSMode) {
+
+                               *pBuf = SK_MS_MODE_INDETERMINATED;
+                       }
+                       break;
+
+               case OID_SKGE_PHY_OPERATION_STATUS:
+                       /* Check if it is the first active port */
+                       if (*pBuf == 0) {
+
+                               *pBuf = pPrt->PMSStatus;
+                               continue;
+                       }
+
+                       /*
+                        * If we find an active port with a different master/
+                        * slave status than the first one, we return a
+                        * value that indicates that the status is
+                        * indeterminated.
+                        */
+                       if (*pBuf != pPrt->PMSStatus) {
+
+                               *pBuf = SK_MS_STAT_INDETERMINATED;
+                       }
+                       break;
+               
+               case OID_SKGE_SPEED_MODE:
+                       /* Check if it is the first active port */
+                       if (*pBuf == 0) {
+
+                               *pBuf = pPrt->PLinkSpeed;
+                               continue;
+                       }
+
+                       /*
+                        * If we find an active port with a different flow
+                        * control mode than the first one, we return a value
+                        * that indicates that the mode is indeterminated.
+                        */
+                       if (*pBuf != pPrt->PLinkSpeed) {
+
+                               *pBuf = SK_LSPEED_INDETERMINATED;
+                       }
+                       break;
+               
+               case OID_SKGE_SPEED_STATUS:
+                       /* Check if it is the first active port */
+                       if (*pBuf == 0) {
+
+                               *pBuf = pPrt->PLinkSpeedUsed;
+                               continue;
+                       }
+
+                       /*
+                        * If we find an active port with a different flow
+                        * control status than the first one, we return a
+                        * value that indicates that the status is
+                        * indeterminated.
+                        */
+                       if (*pBuf != pPrt->PLinkSpeedUsed) {
+
+                               *pBuf = SK_LSPEED_STAT_INDETERMINATED;
+                       }
+                       break;
+               }
+       }
+
+       /*
+        * If no port is active return an indeterminated answer
+        */
+       if (!PortActiveFlag) {
+
+               switch (Id) {
+
+               case OID_SKGE_LINK_CAP:
+                       *pBuf = SK_LMODE_CAP_INDETERMINATED;
+                       break;
+
+               case OID_SKGE_LINK_MODE:
+                       *pBuf = SK_LMODE_INDETERMINATED;
+                       break;
+
+               case OID_SKGE_LINK_MODE_STATUS:
+                       *pBuf = SK_LMODE_STAT_INDETERMINATED;
+                       break;
+
+               case OID_SKGE_LINK_STATUS:
+                       *pBuf = SK_PNMI_RLMT_LSTAT_INDETERMINATED;
+                       break;
+
+               case OID_SKGE_FLOWCTRL_CAP:
+               case OID_SKGE_FLOWCTRL_MODE:
+                       *pBuf = SK_FLOW_MODE_INDETERMINATED;
+                       break;
+
+               case OID_SKGE_FLOWCTRL_STATUS:
+                       *pBuf = SK_FLOW_STAT_INDETERMINATED;
+                       break;
+                       
+               case OID_SKGE_PHY_OPERATION_CAP:
+                       *pBuf = SK_MS_CAP_INDETERMINATED;
+                       break;
+
+               case OID_SKGE_PHY_OPERATION_MODE:
+                       *pBuf = SK_MS_MODE_INDETERMINATED;
+                       break;
+
+               case OID_SKGE_PHY_OPERATION_STATUS:
+                       *pBuf = SK_MS_STAT_INDETERMINATED;
+                       break;
+               case OID_SKGE_SPEED_CAP:
+                       *pBuf = SK_LSPEED_CAP_INDETERMINATED;
+                       break;
+
+               case OID_SKGE_SPEED_MODE:
+                       *pBuf = SK_LSPEED_INDETERMINATED;
+                       break;
+
+               case OID_SKGE_SPEED_STATUS:
+                       *pBuf = SK_LSPEED_STAT_INDETERMINATED;
+                       break;
+               }
+       }
+}
+
+/*****************************************************************************
+ *
+ * CalculateLinkStatus - Determins the link status of a physical port
+ *
+ * Description:
+ *     Determins the link status the following way:
+ *       LSTAT_PHY_DOWN:  Link is down
+ *       LSTAT_AUTONEG:   Auto-negotiation failed
+ *       LSTAT_LOG_DOWN:  Link is up but RLMT did not yet put the port
+ *                        logically up.
+ *       LSTAT_LOG_UP:    RLMT marked the port as up
+ *
+ * Returns:
+ *     Link status of physical port
+ */
+PNMI_STATIC SK_U8 CalculateLinkStatus(
+SK_AC *pAC,                    /* Pointer to adapter context */
+SK_IOC IoC,                    /* IO context handle */
+unsigned int PhysPortIndex)    /* Physical port index */
+{
+       SK_U8   Result;
+
+       if (!pAC->GIni.GP[PhysPortIndex].PHWLinkUp) {
+
+               Result = SK_PNMI_RLMT_LSTAT_PHY_DOWN;
+       }
+       else if (pAC->GIni.GP[PhysPortIndex].PAutoNegFail > 0) {
+
+               Result = SK_PNMI_RLMT_LSTAT_AUTONEG;
+                               }
+       else if (!pAC->Rlmt.Port[PhysPortIndex].PortDown) {
+
+               Result = SK_PNMI_RLMT_LSTAT_LOG_UP;
+       }
+       else {
+               Result = SK_PNMI_RLMT_LSTAT_LOG_DOWN;
+       }
+
+       return (Result);
+}
+
+/*****************************************************************************
+ *
+ * CalculateLinkModeStatus - Determins the link mode status of a phys. port
+ *
+ * Description:
+ *     The COMMON module only tells us if the mode is half or full duplex.
+ *     But in the decade of auto sensing it is useful for the user to
+ *     know if the mode was negotiated or forced. Therefore we have a
+ *     look to the mode, which was last used by the negotiation process.
+ *
+ * Returns:
+ *     The link mode status
+ */
+PNMI_STATIC SK_U8 CalculateLinkModeStatus(
+SK_AC *pAC,                    /* Pointer to adapter context */
+SK_IOC IoC,                    /* IO context handle */
+unsigned int PhysPortIndex)    /* Physical port index */
+{
+       SK_U8   Result;
+
+       /* Get the current mode, which can be full or half duplex */
+       Result = pAC->GIni.GP[PhysPortIndex].PLinkModeStatus;
+
+       /* Check if no valid mode could be found (link is down) */
+       if (Result < SK_LMODE_STAT_HALF) {
+
+               Result = SK_LMODE_STAT_UNKNOWN;
+       }
+       else if (pAC->GIni.GP[PhysPortIndex].PLinkMode >= SK_LMODE_AUTOHALF) {
+
+               /*
+                * Auto-negotiation was used to bring up the link. Change
+                * the already found duplex status that it indicates
+                * auto-negotiation was involved.
+                */
+               if (Result == SK_LMODE_STAT_HALF) {
+
+                       Result = SK_LMODE_STAT_AUTOHALF;
+               }
+               else if (Result == SK_LMODE_STAT_FULL) {
+
+                       Result = SK_LMODE_STAT_AUTOFULL;
+               }
+       }
+
+       return (Result);
+}
+
+/*****************************************************************************
+ *
+ * GetVpdKeyArr - Obtain an array of VPD keys
+ *
+ * Description:
+ *     Read the VPD keys and build an array of VPD keys, which are
+ *     easy to access.
+ *
+ * Returns:
+ *     SK_PNMI_ERR_OK       Task successfully performed.
+ *     SK_PNMI_ERR_GENERAL  Something went wrong.
+ */
+PNMI_STATIC int GetVpdKeyArr(
+SK_AC *pAC,            /* Pointer to adapter context */
+SK_IOC IoC,            /* IO context handle */
+char *pKeyArr,         /* Ptr KeyArray */
+unsigned int KeyArrLen,        /* Length of array in bytes */
+unsigned int *pKeyNo)  /* Number of keys */
+{
+       unsigned int            BufKeysLen = SK_PNMI_VPD_BUFSIZE;
+       char                    BufKeys[SK_PNMI_VPD_BUFSIZE];
+       unsigned int            StartOffset;
+       unsigned int            Offset;
+       int                     Index;
+       int                     Ret;
+
+
+       SK_MEMSET(pKeyArr, 0, KeyArrLen);
+
+       /*
+        * Get VPD key list
+        */
+       Ret = VpdKeys(pAC, IoC, (char *)&BufKeys, (int *)&BufKeysLen,
+               (int *)pKeyNo);
+       if (Ret > 0) {
+
+               SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR014,
+                       SK_PNMI_ERR014MSG);
+
+               return (SK_PNMI_ERR_GENERAL);
+       }
+       /* If no keys are available return now */
+       if (*pKeyNo == 0 || BufKeysLen == 0) {
+
+               return (SK_PNMI_ERR_OK);
+       }
+       /*
+        * If the key list is too long for us trunc it and give a
+        * errorlog notification. This case should not happen because
+        * the maximum number of keys is limited due to RAM limitations
+        */
+       if (*pKeyNo > SK_PNMI_VPD_ENTRIES) {
+
+               SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR015,
+                       SK_PNMI_ERR015MSG);
+
+               *pKeyNo = SK_PNMI_VPD_ENTRIES;
+       }
+
+       /*
+        * Now build an array of fixed string length size and copy
+        * the keys together.
+        */
+       for (Index = 0, StartOffset = 0, Offset = 0; Offset < BufKeysLen;
+               Offset ++) {
+
+               if (BufKeys[Offset] != 0) {
+
+                       continue;
+               }
+
+               if (Offset - StartOffset > SK_PNMI_VPD_KEY_SIZE) {
+
+                       SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR016,
+                               SK_PNMI_ERR016MSG);
+                       return (SK_PNMI_ERR_GENERAL);
+               }
+
+               SK_STRNCPY(pKeyArr + Index * SK_PNMI_VPD_KEY_SIZE,
+                       &BufKeys[StartOffset], SK_PNMI_VPD_KEY_SIZE);
+
+               Index ++;
+               StartOffset = Offset + 1;
+       }
+
+       /* Last key not zero terminated? Get it anyway */
+       if (StartOffset < Offset) {
+
+               SK_STRNCPY(pKeyArr + Index * SK_PNMI_VPD_KEY_SIZE,
+                       &BufKeys[StartOffset], SK_PNMI_VPD_KEY_SIZE);
+       }
+
+       return (SK_PNMI_ERR_OK);
+}
+
+/*****************************************************************************
+ *
+ * SirqUpdate - Let the SIRQ update its internal values
+ *
+ * Description:
+ *     Just to be sure that the SIRQ module holds its internal data
+ *     structures up to date, we send an update event before we make
+ *     any access.
+ *
+ * Returns:
+ *     SK_PNMI_ERR_OK       Task successfully performed.
+ *     SK_PNMI_ERR_GENERAL  Something went wrong.
+ */
+PNMI_STATIC int SirqUpdate(
+SK_AC *pAC,    /* Pointer to adapter context */
+SK_IOC IoC)    /* IO context handle */
+{
+       SK_EVPARA       EventParam;
+
+
+       /* Was the module already updated during the current PNMI call? */
+       if (pAC->Pnmi.SirqUpdatedFlag > 0) {
+
+               return (SK_PNMI_ERR_OK);
+       }
+
+       /* Send an synchronuous update event to the module */
+       SK_MEMSET((char *)&EventParam, 0, sizeof(EventParam));
+       if (SkGeSirqEvent(pAC, IoC, SK_HWEV_UPDATE_STAT, EventParam) > 0) {
+
+               SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR047,
+                       SK_PNMI_ERR047MSG);
+
+               return (SK_PNMI_ERR_GENERAL);
+       }
+
+       return (SK_PNMI_ERR_OK);
+}
+
+/*****************************************************************************
+ *
+ * RlmtUpdate - Let the RLMT update its internal values
+ *
+ * Description:
+ *     Just to be sure that the RLMT module holds its internal data
+ *     structures up to date, we send an update event before we make
+ *     any access.
+ *
+ * Returns:
+ *     SK_PNMI_ERR_OK       Task successfully performed.
+ *     SK_PNMI_ERR_GENERAL  Something went wrong.
+ */
+PNMI_STATIC int RlmtUpdate(
+SK_AC *pAC,    /* Pointer to adapter context */
+SK_IOC IoC,    /* IO context handle */
+SK_U32 NetIndex)       /* NetIndex (0..n), in single net mode allways zero */
+{
+       SK_EVPARA       EventParam;
+
+
+       /* Was the module already updated during the current PNMI call? */
+       if (pAC->Pnmi.RlmtUpdatedFlag > 0) {
+
+               return (SK_PNMI_ERR_OK);
+       }
+
+       /* Send an synchronuous update event to the module */
+       SK_MEMSET((char *)&EventParam, 0, sizeof(EventParam));
+       EventParam.Para32[0] = NetIndex;
+       EventParam.Para32[1] = (SK_U32)-1;
+       if (SkRlmtEvent(pAC, IoC, SK_RLMT_STATS_UPDATE, EventParam) > 0) {
+
+               SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR048,
+                       SK_PNMI_ERR048MSG);
+
+               return (SK_PNMI_ERR_GENERAL);
+       }
+
+       return (SK_PNMI_ERR_OK);
+}
+
+/*****************************************************************************
+ *
+ * MacUpdate - Force the XMAC to output the current statistic
+ *
+ * Description:
+ *     The XMAC holds its statistic internally. To obtain the current
+ *     values we must send a command so that the statistic data will
+ *     be written to a predefined memory area on the adapter.
+ *
+ * Returns:
+ *     SK_PNMI_ERR_OK       Task successfully performed.
+ *     SK_PNMI_ERR_GENERAL  Something went wrong.
+ */
+PNMI_STATIC int MacUpdate(
+SK_AC *pAC,            /* Pointer to adapter context */
+SK_IOC IoC,            /* IO context handle */
+unsigned int FirstMac, /* Index of the first Mac to be updated */
+unsigned int LastMac)  /* Index of the last Mac to be updated */
+{
+       unsigned int    MacIndex;
+
+       /*
+        * Were the statistics already updated during the
+        * current PNMI call?
+        */
+       if (pAC->Pnmi.MacUpdatedFlag > 0) {
+
+               return (SK_PNMI_ERR_OK);
+       }
+
+       /* Send an update command to all MACs specified */
+       for (MacIndex = FirstMac; MacIndex <= LastMac; MacIndex ++) {
+
+               /*
+                * 2002-09-13 pweber:   Freeze the current SW counters.
+                *                      (That should be done as close as
+                *                      possible to the update of the
+                *                      HW counters)
+                */
+               if (pAC->GIni.GIMacType == SK_MAC_XMAC) {
+                       pAC->Pnmi.BufPort[MacIndex] = pAC->Pnmi.Port[MacIndex];
+               }
+                       
+               /* 2002-09-13 pweber:  Update the HW counter  */
+               if (pAC->GIni.GIFunc.pFnMacUpdateStats(pAC, IoC, MacIndex) != 0) {
+
+                       return (SK_PNMI_ERR_GENERAL);
+               }
+       }
+
+       return (SK_PNMI_ERR_OK);
+}
+
+/*****************************************************************************
+ *
+ * GetStatVal - Retrieve an XMAC statistic counter
+ *
+ * Description:
+ *     Retrieves the statistic counter of a virtual or physical port. The
+ *     virtual port is identified by the index 0. It consists of all
+ *     currently active ports. To obtain the counter value for this port
+ *     we must add the statistic counter of all active ports. To grant
+ *     continuous counter values for the virtual port even when port
+ *     switches occur we must additionally add a delta value, which was
+ *     calculated during a SK_PNMI_EVT_RLMT_ACTIVE_UP event.
+ *
+ * Returns:
+ *     Requested statistic value
+ */
+PNMI_STATIC SK_U64 GetStatVal(
+SK_AC *pAC,                                    /* Pointer to adapter context */
+SK_IOC IoC,                                    /* IO context handle */
+unsigned int LogPortIndex,     /* Index of the logical Port to be processed */
+unsigned int StatIndex,                /* Index to statistic value */
+SK_U32 NetIndex)       /* NetIndex (0..n), in single net mode allways zero */
+{
+       unsigned int    PhysPortIndex;
+       unsigned int    PhysPortMax;
+       SK_U64                  Val = 0;
+
+
+       if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) {   /* Dual net mode */
+
+               PhysPortIndex = NetIndex;
+               
+               Val = GetPhysStatVal(pAC, IoC, PhysPortIndex, StatIndex);
+       }
+       else {  /* Single Net mode */
+
+               if (LogPortIndex == 0) {
+
+                       PhysPortMax = pAC->GIni.GIMacsFound;
+
+                       /* Add counter of all active ports */
+                       for (PhysPortIndex = 0; PhysPortIndex < PhysPortMax;
+                               PhysPortIndex ++) {
+
+                               if (pAC->Pnmi.Port[PhysPortIndex].ActiveFlag) {
+
+                                       Val += GetPhysStatVal(pAC, IoC, PhysPortIndex, StatIndex);
+                               }
+                       }
+
+                       /* Correct value because of port switches */
+                       Val += pAC->Pnmi.VirtualCounterOffset[StatIndex];
+               }
+               else {
+                       /* Get counter value of physical port */
+                       PhysPortIndex = SK_PNMI_PORT_LOG2PHYS(pAC, LogPortIndex);
+                       
+                       Val = GetPhysStatVal(pAC, IoC, PhysPortIndex, StatIndex);
+               }
+       }
+       return (Val);
+}
+
+/*****************************************************************************
+ *
+ * GetPhysStatVal - Get counter value for physical port
+ *
+ * Description:
+ *     Builds a 64bit counter value. Except for the octet counters
+ *     the lower 32bit are counted in hardware and the upper 32bit
+ *     in software by monitoring counter overflow interrupts in the
+ *     event handler. To grant continous counter values during XMAC
+ *     resets (caused by a workaround) we must add a delta value.
+ *     The delta was calculated in the event handler when a
+ *     SK_PNMI_EVT_XMAC_RESET was received.
+ *
+ * Returns:
+ *     Counter value
+ */
+PNMI_STATIC SK_U64 GetPhysStatVal(
+SK_AC *pAC,                                    /* Pointer to adapter context */
+SK_IOC IoC,                                    /* IO context handle */
+unsigned int PhysPortIndex,    /* Index of the logical Port to be processed */
+unsigned int StatIndex)                /* Index to statistic value */
+{
+       SK_U64  Val = 0;
+       SK_U32  LowVal = 0;
+       SK_U32  HighVal = 0;
+       SK_U16  Word;
+       int             MacType;
+       unsigned int HelpIndex;
+       SK_GEPORT       *pPrt;
+       
+       SK_PNMI_PORT    *pPnmiPrt;
+       SK_GEMACFUNC    *pFnMac;
+       
+       pPrt = &pAC->GIni.GP[PhysPortIndex];
+       
+       MacType = pAC->GIni.GIMacType;
+       
+       /* 2002-09-17 pweber: For XMAC, use the frozen SW counters (BufPort) */
+       if (MacType == SK_MAC_XMAC) {
+               pPnmiPrt = &pAC->Pnmi.BufPort[PhysPortIndex];
+       }
+       else {
+               pPnmiPrt = &pAC->Pnmi.Port[PhysPortIndex];
+       }
+       
+       pFnMac   = &pAC->GIni.GIFunc;
+
+       switch (StatIndex) {
+       case SK_PNMI_HTX:
+               if (MacType == SK_MAC_GMAC) {
+                       (void)pFnMac->pFnMacStatistic(pAC, IoC, PhysPortIndex,
+                                                       StatAddr[SK_PNMI_HTX_BROADCAST][MacType].Reg,
+                                                       &LowVal);
+                       (void)pFnMac->pFnMacStatistic(pAC, IoC, PhysPortIndex,
+                                                       StatAddr[SK_PNMI_HTX_MULTICAST][MacType].Reg,
+                                                       &HighVal);
+                       LowVal += HighVal;
+                       (void)pFnMac->pFnMacStatistic(pAC, IoC, PhysPortIndex,
+                                                       StatAddr[SK_PNMI_HTX_UNICAST][MacType].Reg,
+                                                       &HighVal);
+                       LowVal += HighVal;
+               }
+               else {
+                       (void)pFnMac->pFnMacStatistic(pAC, IoC, PhysPortIndex,
+                                                                                 StatAddr[StatIndex][MacType].Reg,
+                                                                                 &LowVal);
+               }
+               HighVal = pPnmiPrt->CounterHigh[StatIndex];
+               break;
+       
+       case SK_PNMI_HRX:
+               if (MacType == SK_MAC_GMAC) {
+                       (void)pFnMac->pFnMacStatistic(pAC, IoC, PhysPortIndex,
+                                                       StatAddr[SK_PNMI_HRX_BROADCAST][MacType].Reg,
+                                                       &LowVal);
+                       (void)pFnMac->pFnMacStatistic(pAC, IoC, PhysPortIndex,
+                                                       StatAddr[SK_PNMI_HRX_MULTICAST][MacType].Reg,
+                                                       &HighVal);
+                       LowVal += HighVal;
+                       (void)pFnMac->pFnMacStatistic(pAC, IoC, PhysPortIndex,
+                                                       StatAddr[SK_PNMI_HRX_UNICAST][MacType].Reg,
+                                                       &HighVal);
+                       LowVal += HighVal;
+               }
+               else {
+                       (void)pFnMac->pFnMacStatistic(pAC, IoC, PhysPortIndex,
+                                                                                 StatAddr[StatIndex][MacType].Reg,
+                                                                                 &LowVal);
+               }
+               HighVal = pPnmiPrt->CounterHigh[StatIndex];
+               break;
+
+       case SK_PNMI_HTX_OCTET:
+       case SK_PNMI_HRX_OCTET:
+               (void)pFnMac->pFnMacStatistic(pAC, IoC, PhysPortIndex,
+                                                                         StatAddr[StatIndex][MacType].Reg,
+                                                                         &HighVal);
+               (void)pFnMac->pFnMacStatistic(pAC, IoC, PhysPortIndex,
+                                                                         StatAddr[StatIndex + 1][MacType].Reg,
+                                                                         &LowVal);
+               break;
+
+       case SK_PNMI_HTX_BURST:
+       case SK_PNMI_HTX_EXCESS_DEF:
+       case SK_PNMI_HTX_CARRIER:
+               /* Not supported by GMAC */
+               if (MacType == SK_MAC_GMAC) {
+                       return (Val);
+               }
+
+               (void)pFnMac->pFnMacStatistic(pAC, IoC, PhysPortIndex,
+                                                                         StatAddr[StatIndex][MacType].Reg,
+                                                                         &LowVal);
+               HighVal = pPnmiPrt->CounterHigh[StatIndex];
+               break;
+
+       case SK_PNMI_HTX_MACC:
+               /* GMAC only supports PAUSE MAC control frames */
+               if (MacType == SK_MAC_GMAC) {
+                       HelpIndex = SK_PNMI_HTX_PMACC;
+               }
+               else {
+                       HelpIndex = StatIndex;
+               }
+               
+               (void)pFnMac->pFnMacStatistic(pAC, IoC, PhysPortIndex,
+                                                               StatAddr[HelpIndex][MacType].Reg,
+                                                               &LowVal);
+
+               HighVal = pPnmiPrt->CounterHigh[StatIndex];
+               break;
+
+       case SK_PNMI_HTX_COL:
+       case SK_PNMI_HRX_UNDERSIZE:
+               /* Not supported by XMAC */
+               if (MacType == SK_MAC_XMAC) {
+                       return (Val);
+               }
+
+               (void)pFnMac->pFnMacStatistic(pAC, IoC, PhysPortIndex,
+                                                                         StatAddr[StatIndex][MacType].Reg,
+                                                                         &LowVal);
+               HighVal = pPnmiPrt->CounterHigh[StatIndex];
+               break;
+
+       case SK_PNMI_HTX_DEFFERAL:
+               /* Not supported by GMAC */
+               if (MacType == SK_MAC_GMAC) {
+                       return (Val);
+               }
+               
+               /*
+                * XMAC counts frames with deferred transmission
+                * even in full-duplex mode.
+                *
+                * In full-duplex mode the counter remains constant!
+                */
+               if ((pPrt->PLinkModeStatus == SK_LMODE_STAT_AUTOFULL) ||
+                       (pPrt->PLinkModeStatus == SK_LMODE_STAT_FULL)) {
+
+                       LowVal = 0;
+                       HighVal = 0;
+               }
+               else {
+                       /* Otherwise get contents of hardware register */
+                       (void)pFnMac->pFnMacStatistic(pAC, IoC, PhysPortIndex,
+                                                                                 StatAddr[StatIndex][MacType].Reg,
+                                                                                 &LowVal);
+                       HighVal = pPnmiPrt->CounterHigh[StatIndex];
+               }
+               break;
+
+       case SK_PNMI_HRX_BADOCTET:
+               /* Not supported by XMAC */
+               if (MacType == SK_MAC_XMAC) {
+                       return (Val);
+               }
+
+               (void)pFnMac->pFnMacStatistic(pAC, IoC, PhysPortIndex,
+                                                                         StatAddr[StatIndex][MacType].Reg,
+                                                                         &HighVal);
+               (void)pFnMac->pFnMacStatistic(pAC, IoC, PhysPortIndex,
+                                                                         StatAddr[StatIndex + 1][MacType].Reg,
+                                      &LowVal);
+               break;
+
+       case SK_PNMI_HTX_OCTETLOW:
+       case SK_PNMI_HRX_OCTETLOW:
+       case SK_PNMI_HRX_BADOCTETLOW:
+               return (Val);
+
+       case SK_PNMI_HRX_LONGFRAMES:
+               /* For XMAC the SW counter is managed by PNMI */
+               if (MacType == SK_MAC_XMAC) {
+                       return (pPnmiPrt->StatRxLongFrameCts);
+               }
+               
+               (void)pFnMac->pFnMacStatistic(pAC, IoC, PhysPortIndex,
+                                                                         StatAddr[StatIndex][MacType].Reg,
+                                                                         &LowVal);
+               HighVal = pPnmiPrt->CounterHigh[StatIndex];
+               break;
+               
+       case SK_PNMI_HRX_TOO_LONG:
+               (void)pFnMac->pFnMacStatistic(pAC, IoC, PhysPortIndex,
+                                                               StatAddr[StatIndex][MacType].Reg,
+                                                               &LowVal);
+               HighVal = pPnmiPrt->CounterHigh[StatIndex];
+               
+               Val = (((SK_U64)HighVal << 32) | (SK_U64)LowVal);
+
+               if (MacType == SK_MAC_GMAC) {
+                       /* For GMAC the SW counter is additionally managed by PNMI */
+                       Val += pPnmiPrt->StatRxFrameTooLongCts;
+               }
+               else {
+                       /*
+                        * Frames longer than IEEE 802.3 frame max size are counted
+                        * by XMAC in frame_too_long counter even reception of long
+                        * frames was enabled and the frame was correct.
+                        * So correct the value by subtracting RxLongFrame counter.
+                        */
+                       Val -= pPnmiPrt->StatRxLongFrameCts;
+               }
+
+               LowVal = (SK_U32)Val;
+               HighVal = (SK_U32)(Val >> 32);
+               break;
+               
+       case SK_PNMI_HRX_SHORTS:
+               /* Not supported by GMAC */
+               if (MacType == SK_MAC_GMAC) {
+                       /* GM_RXE_FRAG?? */
+                       return (Val);
+               }
+               
+               /*
+                * XMAC counts short frame errors even if link down (#10620)
+                *
+                * If link-down the counter remains constant
+                */
+               if (pPrt->PLinkModeStatus != SK_LMODE_STAT_UNKNOWN) {
+
+                       /* Otherwise get incremental difference */
+                       (void)pFnMac->pFnMacStatistic(pAC, IoC, PhysPortIndex,
+                                                                                 StatAddr[StatIndex][MacType].Reg,
+                                                                                 &LowVal);
+                       HighVal = pPnmiPrt->CounterHigh[StatIndex];
+
+                       Val = (((SK_U64)HighVal << 32) | (SK_U64)LowVal);
+                       Val -= pPnmiPrt->RxShortZeroMark;
+
+                       LowVal = (SK_U32)Val;
+                       HighVal = (SK_U32)(Val >> 32);
+               }
+               break;
+
+       case SK_PNMI_HRX_MACC:
+       case SK_PNMI_HRX_MACC_UNKWN:
+       case SK_PNMI_HRX_BURST:
+       case SK_PNMI_HRX_MISSED:
+       case SK_PNMI_HRX_FRAMING:
+       case SK_PNMI_HRX_CARRIER:
+       case SK_PNMI_HRX_IRLENGTH:
+       case SK_PNMI_HRX_SYMBOL:
+       case SK_PNMI_HRX_CEXT:
+               /* Not supported by GMAC */
+               if (MacType == SK_MAC_GMAC) {
+                       return (Val);
+               }
+
+               (void)pFnMac->pFnMacStatistic(pAC, IoC, PhysPortIndex,
+                                                                         StatAddr[StatIndex][MacType].Reg,
+                                                                         &LowVal);
+               HighVal = pPnmiPrt->CounterHigh[StatIndex];
+               break;
+
+       case SK_PNMI_HRX_PMACC_ERR:
+               /* For GMAC the SW counter is managed by PNMI */
+               if (MacType == SK_MAC_GMAC) {
+                       return (pPnmiPrt->StatRxPMaccErr);
+               }
+               
+               (void)pFnMac->pFnMacStatistic(pAC, IoC, PhysPortIndex,
+                                                                         StatAddr[StatIndex][MacType].Reg,
+                                                                         &LowVal);
+               HighVal = pPnmiPrt->CounterHigh[StatIndex];
+               break;
+
+       /* SW counter managed by PNMI */
+       case SK_PNMI_HTX_SYNC:
+               LowVal = (SK_U32)pPnmiPrt->StatSyncCts;
+               HighVal = (SK_U32)(pPnmiPrt->StatSyncCts >> 32);
+               break;
+
+       /* SW counter managed by PNMI */
+       case SK_PNMI_HTX_SYNC_OCTET:
+               LowVal = (SK_U32)pPnmiPrt->StatSyncOctetsCts;
+               HighVal = (SK_U32)(pPnmiPrt->StatSyncOctetsCts >> 32);
+               break;
+
+       case SK_PNMI_HRX_FCS:
+               /*
+                * Broadcom filters FCS errors and counts it in
+                * Receive Error Counter register
+                */
+               if (pPrt->PhyType == SK_PHY_BCOM) {
+                       /* do not read while not initialized (PHY_READ hangs!)*/
+                       if (pPrt->PState != SK_PRT_RESET) {
+                               SkXmPhyRead(pAC, IoC, PhysPortIndex, PHY_BCOM_RE_CTR, &Word);
+                               
+                               LowVal = Word;
+                       }
+                       HighVal = pPnmiPrt->CounterHigh[StatIndex];
+               }
+               else {
+                       (void)pFnMac->pFnMacStatistic(pAC, IoC, PhysPortIndex,
+                                                                                 StatAddr[StatIndex][MacType].Reg,
+                                                                                 &LowVal);
+                       HighVal = pPnmiPrt->CounterHigh[StatIndex];
+               }
+               break;
+
+       default:
+               (void)pFnMac->pFnMacStatistic(pAC, IoC, PhysPortIndex,
+                                                                         StatAddr[StatIndex][MacType].Reg,
+                                                                         &LowVal);
+               HighVal = pPnmiPrt->CounterHigh[StatIndex];
+               break;
+       }
+
+       Val = (((SK_U64)HighVal << 32) | (SK_U64)LowVal);
+
+       /* Correct value because of possible XMAC reset. XMAC Errata #2 */
+       Val += pPnmiPrt->CounterOffset[StatIndex];
+
+       return (Val);
+}
+
+/*****************************************************************************
+ *
+ * ResetCounter - Set all counters and timestamps to zero
+ *
+ * Description:
+ *     Notifies other common modules which store statistic data to
+ *     reset their counters and finally reset our own counters.
+ *
+ * Returns:
+ *     Nothing
+ */
+PNMI_STATIC void ResetCounter(
+SK_AC *pAC,            /* Pointer to adapter context */
+SK_IOC IoC,            /* IO context handle */
+SK_U32 NetIndex)
+{
+       unsigned int    PhysPortIndex;
+       SK_EVPARA       EventParam;
+
+
+       SK_MEMSET((char *)&EventParam, 0, sizeof(EventParam));
+
+       /* Notify sensor module */
+       SkEventQueue(pAC, SKGE_I2C, SK_I2CEV_CLEAR, EventParam);
+
+       /* Notify RLMT module */
+       EventParam.Para32[0] = NetIndex;
+       EventParam.Para32[1] = (SK_U32)-1;
+       SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_STATS_CLEAR, EventParam);
+       EventParam.Para32[1] = 0;
+
+       /* Notify SIRQ module */
+       SkEventQueue(pAC, SKGE_HWAC, SK_HWEV_CLEAR_STAT, EventParam);
+
+       /* Notify CSUM module */
+#ifdef SK_USE_CSUM
+       EventParam.Para32[0] = NetIndex;
+       EventParam.Para32[1] = (SK_U32)-1;
+       SkEventQueue(pAC, SKGE_CSUM, SK_CSUM_EVENT_CLEAR_PROTO_STATS,
+               EventParam);
+#endif /* SK_USE_CSUM */
+       
+       /* Clear XMAC statistic */
+       for (PhysPortIndex = 0; PhysPortIndex <
+               (unsigned int)pAC->GIni.GIMacsFound; PhysPortIndex ++) {
+
+               (void)pAC->GIni.GIFunc.pFnMacResetCounter(pAC, IoC, PhysPortIndex);
+
+               SK_MEMSET((char *)&pAC->Pnmi.Port[PhysPortIndex].CounterHigh,
+                       0, sizeof(pAC->Pnmi.Port[PhysPortIndex].CounterHigh));
+               SK_MEMSET((char *)&pAC->Pnmi.Port[PhysPortIndex].
+                       CounterOffset, 0, sizeof(pAC->Pnmi.Port[
+                       PhysPortIndex].CounterOffset));
+               SK_MEMSET((char *)&pAC->Pnmi.Port[PhysPortIndex].StatSyncCts,
+                       0, sizeof(pAC->Pnmi.Port[PhysPortIndex].StatSyncCts));
+               SK_MEMSET((char *)&pAC->Pnmi.Port[PhysPortIndex].
+                       StatSyncOctetsCts, 0, sizeof(pAC->Pnmi.Port[
+                       PhysPortIndex].StatSyncOctetsCts));
+               SK_MEMSET((char *)&pAC->Pnmi.Port[PhysPortIndex].
+                       StatRxLongFrameCts, 0, sizeof(pAC->Pnmi.Port[
+                       PhysPortIndex].StatRxLongFrameCts));
+               SK_MEMSET((char *)&pAC->Pnmi.Port[PhysPortIndex].
+                                 StatRxFrameTooLongCts, 0, sizeof(pAC->Pnmi.Port[
+                       PhysPortIndex].StatRxFrameTooLongCts));
+               SK_MEMSET((char *)&pAC->Pnmi.Port[PhysPortIndex].
+                                 StatRxPMaccErr, 0, sizeof(pAC->Pnmi.Port[
+                       PhysPortIndex].StatRxPMaccErr));
+       }
+
+       /*
+        * Clear local statistics
+        */
+       SK_MEMSET((char *)&pAC->Pnmi.VirtualCounterOffset, 0,
+                 sizeof(pAC->Pnmi.VirtualCounterOffset));
+       pAC->Pnmi.RlmtChangeCts = 0;
+       pAC->Pnmi.RlmtChangeTime = 0;
+       SK_MEMSET((char *)&pAC->Pnmi.RlmtChangeEstimate.EstValue[0], 0,
+               sizeof(pAC->Pnmi.RlmtChangeEstimate.EstValue));
+       pAC->Pnmi.RlmtChangeEstimate.EstValueIndex = 0;
+       pAC->Pnmi.RlmtChangeEstimate.Estimate = 0;
+       pAC->Pnmi.Port[NetIndex].TxSwQueueMax = 0;
+       pAC->Pnmi.Port[NetIndex].TxRetryCts = 0;
+       pAC->Pnmi.Port[NetIndex].RxIntrCts = 0;
+       pAC->Pnmi.Port[NetIndex].TxIntrCts = 0;
+       pAC->Pnmi.Port[NetIndex].RxNoBufCts = 0;
+       pAC->Pnmi.Port[NetIndex].TxNoBufCts = 0;
+       pAC->Pnmi.Port[NetIndex].TxUsedDescrNo = 0;
+       pAC->Pnmi.Port[NetIndex].RxDeliveredCts = 0;
+       pAC->Pnmi.Port[NetIndex].RxOctetsDeliveredCts = 0;
+       pAC->Pnmi.Port[NetIndex].ErrRecoveryCts = 0;
+}
+
+/*****************************************************************************
+ *
+ * GetTrapEntry - Get an entry in the trap buffer
+ *
+ * Description:
+ *     The trap buffer stores various events. A user application somehow
+ *     gets notified that an event occured and retrieves the trap buffer
+ *     contens (or simply polls the buffer). The buffer is organized as
+ *     a ring which stores the newest traps at the beginning. The oldest
+ *     traps are overwritten by the newest ones. Each trap entry has a
+ *     unique number, so that applications may detect new trap entries.
+ *
+ * Returns:
+ *     A pointer to the trap entry
+ */
+PNMI_STATIC char* GetTrapEntry(
+SK_AC *pAC,            /* Pointer to adapter context */
+SK_U32 TrapId,         /* SNMP ID of the trap */
+unsigned int Size)     /* Space needed for trap entry */
+{
+       unsigned int            BufPad = pAC->Pnmi.TrapBufPad;
+       unsigned int            BufFree = pAC->Pnmi.TrapBufFree;
+       unsigned int            Beg = pAC->Pnmi.TrapQueueBeg;
+       unsigned int            End = pAC->Pnmi.TrapQueueEnd;
+       char                    *pBuf = &pAC->Pnmi.TrapBuf[0];
+       int                     Wrap;
+       unsigned int            NeededSpace;
+       unsigned int            EntrySize;
+       SK_U32                  Val32;
+       SK_U64                  Val64;
+
+
+       /* Last byte of entry will get a copy of the entry length */
+       Size ++;
+
+       /*
+        * Calculate needed buffer space */
+       if (Beg >= Size) {
+
+               NeededSpace = Size;
+               Wrap = SK_FALSE;
+       }
+       else {
+               NeededSpace = Beg + Size;
+               Wrap = SK_TRUE;
+       }
+
+       /*
+        * Check if enough buffer space is provided. Otherwise
+        * free some entries. Leave one byte space between begin
+        * and end of buffer to make it possible to detect whether
+        * the buffer is full or empty
+        */
+       while (BufFree < NeededSpace + 1) {
+
+               if (End == 0) {
+
+                       End = SK_PNMI_TRAP_QUEUE_LEN;
+               }
+
+               EntrySize = (unsigned int)*((unsigned char *)pBuf + End - 1);
+               BufFree += EntrySize;
+               End -= EntrySize;
+#ifdef DEBUG
+               SK_MEMSET(pBuf + End, (char)(-1), EntrySize);
+#endif /* DEBUG */
+               if (End == BufPad) {
+#ifdef DEBUG
+                       SK_MEMSET(pBuf, (char)(-1), End);
+#endif /* DEBUG */
+                       BufFree += End;
+                       End = 0;
+                       BufPad = 0;
+               }
+       }
+
+       /*
+        * Insert new entry as first entry. Newest entries are
+        * stored at the beginning of the queue.
+        */
+       if (Wrap) {
+
+               BufPad = Beg;
+               Beg = SK_PNMI_TRAP_QUEUE_LEN - Size;
+       }
+       else {
+               Beg = Beg - Size;
+       }
+       BufFree -= NeededSpace;
+
+       /* Save the current offsets */
+       pAC->Pnmi.TrapQueueBeg = Beg;
+       pAC->Pnmi.TrapQueueEnd = End;
+       pAC->Pnmi.TrapBufPad = BufPad;
+       pAC->Pnmi.TrapBufFree = BufFree;
+
+       /* Initialize the trap entry */
+       *(pBuf + Beg + Size - 1) = (char)Size;
+       *(pBuf + Beg) = (char)Size;
+       Val32 = (pAC->Pnmi.TrapUnique) ++;
+       SK_PNMI_STORE_U32(pBuf + Beg + 1, Val32);
+       SK_PNMI_STORE_U32(pBuf + Beg + 1 + sizeof(SK_U32), TrapId);
+       Val64 = SK_PNMI_HUNDREDS_SEC(SkOsGetTime(pAC));
+       SK_PNMI_STORE_U64(pBuf + Beg + 1 + 2 * sizeof(SK_U32), Val64);
+
+       return (pBuf + Beg);
+}
+
+/*****************************************************************************
+ *
+ * CopyTrapQueue - Copies the trap buffer for the TRAP OID
+ *
+ * Description:
+ *     On a query of the TRAP OID the trap buffer contents will be
+ *     copied continuously to the request buffer, which must be large
+ *     enough. No length check is performed.
+ *
+ * Returns:
+ *     Nothing
+ */
+PNMI_STATIC void CopyTrapQueue(
+SK_AC *pAC,            /* Pointer to adapter context */
+char *pDstBuf)         /* Buffer to which the queued traps will be copied */
+{
+       unsigned int    BufPad = pAC->Pnmi.TrapBufPad;
+       unsigned int    Trap = pAC->Pnmi.TrapQueueBeg;
+       unsigned int    End = pAC->Pnmi.TrapQueueEnd;
+       char            *pBuf = &pAC->Pnmi.TrapBuf[0];
+       unsigned int    Len;
+       unsigned int    DstOff = 0;
+
+
+       while (Trap != End) {
+
+               Len = (unsigned int)*(pBuf + Trap);
+
+               /*
+                * Last byte containing a copy of the length will
+                * not be copied.
+                */
+               *(pDstBuf + DstOff) = (char)(Len - 1);
+               SK_MEMCPY(pDstBuf + DstOff + 1, pBuf + Trap + 1, Len - 2);
+               DstOff += Len - 1;
+
+               Trap += Len;
+               if (Trap == SK_PNMI_TRAP_QUEUE_LEN) {
+
+                       Trap = BufPad;
+               }
+       }
+}
+
+/*****************************************************************************
+ *
+ * GetTrapQueueLen - Get the length of the trap buffer
+ *
+ * Description:
+ *     Evaluates the number of currently stored traps and the needed
+ *     buffer size to retrieve them.
+ *
+ * Returns:
+ *     Nothing
+ */
+PNMI_STATIC void GetTrapQueueLen(
+SK_AC *pAC,            /* Pointer to adapter context */
+unsigned int *pLen,    /* Length in Bytes of all queued traps */
+unsigned int *pEntries)        /* Returns number of trapes stored in queue */
+{
+       unsigned int    BufPad = pAC->Pnmi.TrapBufPad;
+       unsigned int    Trap = pAC->Pnmi.TrapQueueBeg;
+       unsigned int    End = pAC->Pnmi.TrapQueueEnd;
+       char            *pBuf = &pAC->Pnmi.TrapBuf[0];
+       unsigned int    Len;
+       unsigned int    Entries = 0;
+       unsigned int    TotalLen = 0;
+
+
+       while (Trap != End) {
+
+               Len = (unsigned int)*(pBuf + Trap);
+               TotalLen += Len - 1;
+               Entries ++;
+
+               Trap += Len;
+               if (Trap == SK_PNMI_TRAP_QUEUE_LEN) {
+
+                       Trap = BufPad;
+               }
+       }
+
+       *pEntries = Entries;
+       *pLen = TotalLen;
+}
+
+/*****************************************************************************
+ *
+ * QueueSimpleTrap - Store a simple trap to the trap buffer
+ *
+ * Description:
+ *     A simple trap is a trap with now additional data. It consists
+ *     simply of a trap code.
+ *
+ * Returns:
+ *     Nothing
+ */
+PNMI_STATIC void QueueSimpleTrap(
+SK_AC *pAC,            /* Pointer to adapter context */
+SK_U32 TrapId)         /* Type of sensor trap */
+{
+       GetTrapEntry(pAC, TrapId, SK_PNMI_TRAP_SIMPLE_LEN);
+}
+
+/*****************************************************************************
+ *
+ * QueueSensorTrap - Stores a sensor trap in the trap buffer
+ *
+ * Description:
+ *     Gets an entry in the trap buffer and fills it with sensor related
+ *     data.
+ *
+ * Returns:
+ *     Nothing
+ */
+PNMI_STATIC void QueueSensorTrap(
+SK_AC *pAC,                    /* Pointer to adapter context */
+SK_U32 TrapId,                 /* Type of sensor trap */
+unsigned int SensorIndex)      /* Index of sensor which caused the trap */
+{
+       char            *pBuf;
+       unsigned int    Offset;
+       unsigned int    DescrLen;
+       SK_U32          Val32;
+
+
+       /* Get trap buffer entry */
+       DescrLen = SK_STRLEN(pAC->I2c.SenTable[SensorIndex].SenDesc);
+       pBuf = GetTrapEntry(pAC, TrapId,
+               SK_PNMI_TRAP_SENSOR_LEN_BASE + DescrLen);
+       Offset = SK_PNMI_TRAP_SIMPLE_LEN;
+
+       /* Store additionally sensor trap related data */
+       Val32 = OID_SKGE_SENSOR_INDEX;
+       SK_PNMI_STORE_U32(pBuf + Offset, Val32);
+       *(pBuf + Offset + 4) = 4;
+       Val32 = (SK_U32)SensorIndex;
+       SK_PNMI_STORE_U32(pBuf + Offset + 5, Val32);
+       Offset += 9;
+       
+       Val32 = (SK_U32)OID_SKGE_SENSOR_DESCR;
+       SK_PNMI_STORE_U32(pBuf + Offset, Val32);
+       *(pBuf + Offset + 4) = (char)DescrLen;
+       SK_MEMCPY(pBuf + Offset + 5, pAC->I2c.SenTable[SensorIndex].SenDesc,
+               DescrLen);
+       Offset += DescrLen + 5;
+
+       Val32 = OID_SKGE_SENSOR_TYPE;
+       SK_PNMI_STORE_U32(pBuf + Offset, Val32);
+       *(pBuf + Offset + 4) = 1;
+       *(pBuf + Offset + 5) = (char)pAC->I2c.SenTable[SensorIndex].SenType;
+       Offset += 6;
+
+       Val32 = OID_SKGE_SENSOR_VALUE;
+       SK_PNMI_STORE_U32(pBuf + Offset, Val32);
+       *(pBuf + Offset + 4) = 4;
+       Val32 = (SK_U32)pAC->I2c.SenTable[SensorIndex].SenValue;
+       SK_PNMI_STORE_U32(pBuf + Offset + 5, Val32);
+}
+
+/*****************************************************************************
+ *
+ * QueueRlmtNewMacTrap - Store a port switch trap in the trap buffer
+ *
+ * Description:
+ *     Nothing further to explain.
+ *
+ * Returns:
+ *     Nothing
+ */
+PNMI_STATIC void QueueRlmtNewMacTrap(
+SK_AC *pAC,            /* Pointer to adapter context */
+unsigned int ActiveMac)        /* Index (0..n) of the currently active port */
+{
+       char    *pBuf;
+       SK_U32  Val32;
+
+
+       pBuf = GetTrapEntry(pAC, OID_SKGE_TRAP_RLMT_CHANGE_PORT,
+               SK_PNMI_TRAP_RLMT_CHANGE_LEN);
+
+       Val32 = OID_SKGE_RLMT_PORT_ACTIVE;
+       SK_PNMI_STORE_U32(pBuf + SK_PNMI_TRAP_SIMPLE_LEN, Val32);
+       *(pBuf + SK_PNMI_TRAP_SIMPLE_LEN + 4) = 1;
+       *(pBuf + SK_PNMI_TRAP_SIMPLE_LEN + 5) = (char)ActiveMac;
+}
+
+/*****************************************************************************
+ *
+ * QueueRlmtPortTrap - Store port related RLMT trap to trap buffer
+ *
+ * Description:
+ *     Nothing further to explain.
+ *
+ * Returns:
+ *     Nothing
+ */
+PNMI_STATIC void QueueRlmtPortTrap(
+SK_AC *pAC,            /* Pointer to adapter context */
+SK_U32 TrapId,         /* Type of RLMT port trap */
+unsigned int PortIndex)        /* Index of the port, which changed its state */
+{
+       char    *pBuf;
+       SK_U32  Val32;
+
+
+       pBuf = GetTrapEntry(pAC, TrapId, SK_PNMI_TRAP_RLMT_PORT_LEN);
+
+       Val32 = OID_SKGE_RLMT_PORT_INDEX;
+       SK_PNMI_STORE_U32(pBuf + SK_PNMI_TRAP_SIMPLE_LEN, Val32);
+       *(pBuf + SK_PNMI_TRAP_SIMPLE_LEN + 4) = 1;
+       *(pBuf + SK_PNMI_TRAP_SIMPLE_LEN + 5) = (char)PortIndex;
+}
+
+/*****************************************************************************
+ *
+ * CopyMac - Copies a MAC address
+ *
+ * Description:
+ *     Nothing further to explain.
+ *
+ * Returns:
+ *     Nothing
+ */
+PNMI_STATIC void CopyMac(
+char *pDst,            /* Pointer to destination buffer */
+SK_MAC_ADDR *pMac)     /* Pointer of Source */
+{
+       int     i;
+
+
+       for (i = 0; i < sizeof(SK_MAC_ADDR); i ++) {
+
+               *(pDst + i) = pMac->a[i];
+       }
+}
+
+#ifdef SK_POWER_MGMT
+/*****************************************************************************
+ *
+ * PowerManagement - OID handler function of PowerManagement OIDs
+ *
+ * Description:
+ *     The code is simple. No description necessary.
+ *
+ * Returns:
+ *     SK_PNMI_ERR_OK           The request was successfully performed.
+ *     SK_PNMI_ERR_GENERAL      A general severe internal error occured.
+ *     SK_PNMI_ERR_TOO_SHORT    The passed buffer is too short to contain
+ *                              the correct data (e.g. a 32bit value is
+ *                              needed, but a 16 bit value was passed).
+ *     SK_PNMI_ERR_UNKNOWN_INST The requested instance of the OID doesn't
+ *                               exist (e.g. port instance 3 on a two port
+ *                              adapter.
+ */
+
+PNMI_STATIC int PowerManagement(
+SK_AC *pAC,            /* Pointer to adapter context */
+SK_IOC IoC,            /* IO context handle */
+int Action,            /* Get/PreSet/Set action */
+SK_U32 Id,             /* Object ID that is to be processed */
+char *pBuf,            /* Buffer to which to mgmt data will be retrieved */
+unsigned int *pLen,    /* On call: buffer length. On return: used buffer */
+SK_U32 Instance,       /* Instance (1..n) that is to be queried or -1 */
+unsigned int TableIndex, /* Index to the Id table */
+SK_U32 NetIndex)       /* NetIndex (0..n), in single net mode allways zero */
+{
+       
+       SK_U32  RetCode = SK_PNMI_ERR_GENERAL;
+
+       /*
+        * Check instance. We only handle single instance variables
+        */
+       if (Instance != (SK_U32)(-1) && Instance != 1) {
+
+               *pLen = 0;
+               return (SK_PNMI_ERR_UNKNOWN_INST);
+       }
+       
+    
+    /* Check length */
+    switch (Id) {
+
+    case OID_PNP_CAPABILITIES:
+        if (*pLen < sizeof(SK_PNP_CAPABILITIES)) {
+
+            *pLen = sizeof(SK_PNP_CAPABILITIES);
+            return (SK_PNMI_ERR_TOO_SHORT);
+        }
+        break;
+
+       case OID_PNP_SET_POWER:
+    case OID_PNP_QUERY_POWER:
+       if (*pLen < sizeof(SK_DEVICE_POWER_STATE))
+       {
+               *pLen = sizeof(SK_DEVICE_POWER_STATE);
+               return (SK_PNMI_ERR_TOO_SHORT);
+       }
+        break;
+
+    case OID_PNP_ADD_WAKE_UP_PATTERN:
+    case OID_PNP_REMOVE_WAKE_UP_PATTERN:
+               if (*pLen < sizeof(SK_PM_PACKET_PATTERN)) {
+
+                       *pLen = sizeof(SK_PM_PACKET_PATTERN);
+                       return (SK_PNMI_ERR_TOO_SHORT);
+               }
+               break;
+
+    case OID_PNP_ENABLE_WAKE_UP:
+        if (*pLen < sizeof(SK_U32)) {
+
+            *pLen = sizeof(SK_U32);
+            return (SK_PNMI_ERR_TOO_SHORT);
+        }
+        break;
+    }
+       
+    /*
+        * Perform action
+        */
+       if (Action == SK_PNMI_GET) {
+
+               /*
+                * Get value
+                */
+               switch (Id) {
+
+               case OID_PNP_CAPABILITIES:
+                       RetCode = SkPowerQueryPnPCapabilities(pAC, IoC, pBuf, pLen);
+                       break;
+
+               case OID_PNP_QUERY_POWER:
+                       /* The Windows DDK describes: An OID_PNP_QUERY_POWER requests
+                        the miniport to indicate whether it can transition its NIC
+                        to the low-power state.
+                        A miniport driver must always return NDIS_STATUS_SUCCESS
+                        to a query of OID_PNP_QUERY_POWER. */
+                       *pLen = sizeof(SK_DEVICE_POWER_STATE);
+            RetCode = SK_PNMI_ERR_OK;
+                       break;
+
+                       /* NDIS handles these OIDs as write-only.
+                        * So in case of get action the buffer with written length = 0
+                        * is returned
+                        */
+               case OID_PNP_SET_POWER:
+               case OID_PNP_ADD_WAKE_UP_PATTERN:
+               case OID_PNP_REMOVE_WAKE_UP_PATTERN:
+                       *pLen = 0;      
+            RetCode = SK_PNMI_ERR_NOT_SUPPORTED;
+                       break;
+
+               case OID_PNP_ENABLE_WAKE_UP:
+                       RetCode = SkPowerGetEnableWakeUp(pAC, IoC, pBuf, pLen);
+                       break;
+
+               default:
+                       RetCode = SK_PNMI_ERR_GENERAL;
+                       break;
+               }
+
+               return (RetCode);
+       }
+       
+
+       /*
+        * Perform preset or set
+        */
+       
+       /* POWER module does not support PRESET action */
+       if (Action == SK_PNMI_PRESET) {
+               return (SK_PNMI_ERR_OK);
+       }
+
+       switch (Id) {
+       case OID_PNP_SET_POWER:
+               RetCode = SkPowerSetPower(pAC, IoC, pBuf, pLen);        
+               break;
+
+       case OID_PNP_ADD_WAKE_UP_PATTERN:
+               RetCode = SkPowerAddWakeUpPattern(pAC, IoC, pBuf, pLen);        
+               break;
+               
+       case OID_PNP_REMOVE_WAKE_UP_PATTERN:
+               RetCode = SkPowerRemoveWakeUpPattern(pAC, IoC, pBuf, pLen);     
+               break;
+               
+       case OID_PNP_ENABLE_WAKE_UP:
+               RetCode = SkPowerSetEnableWakeUp(pAC, IoC, pBuf, pLen);
+               break;
+               
+       default:
+               RetCode = SK_PNMI_ERR_READ_ONLY;
+       }
+       
+       return (RetCode);
+}
+#endif /* SK_POWER_MGMT */
+
+#ifdef SK_DIAG_SUPPORT
+/*****************************************************************************
+ *
+ * DiagActions - OID handler function of Diagnostic driver 
+ *
+ * Description:
+ *     The code is simple. No description necessary.
+ *
+ * Returns:
+ *     SK_PNMI_ERR_OK           The request was successfully performed.
+ *     SK_PNMI_ERR_GENERAL      A general severe internal error occured.
+ *     SK_PNMI_ERR_TOO_SHORT    The passed buffer is too short to contain
+ *                              the correct data (e.g. a 32bit value is
+ *                              needed, but a 16 bit value was passed).
+ *     SK_PNMI_ERR_UNKNOWN_INST The requested instance of the OID doesn't
+ *                           exist (e.g. port instance 3 on a two port
+ *                              adapter.
+ */
+
+PNMI_STATIC int DiagActions(
+SK_AC *pAC,            /* Pointer to adapter context */
+SK_IOC IoC,            /* IO context handle */
+int Action,            /* GET/PRESET/SET action */
+SK_U32 Id,             /* Object ID that is to be processed */
+char *pBuf,            /* Buffer used for the management data transfer */
+unsigned int *pLen,    /* On call: pBuf buffer length. On return: used buffer */
+SK_U32 Instance,       /* Instance (1..n) that is to be queried or -1 */
+unsigned int TableIndex, /* Index to the Id table */
+SK_U32 NetIndex)       /* NetIndex (0..n), in single net mode always zero */
+{
+
+       SK_U32  DiagStatus;
+       SK_U32  RetCode = SK_PNMI_ERR_GENERAL;
+
+       /*
+        * Check instance. We only handle single instance variables.
+        */
+       if (Instance != (SK_U32)(-1) && Instance != 1) {
+
+               *pLen = 0;
+               return (SK_PNMI_ERR_UNKNOWN_INST);
+       }
+
+       /*
+        * Check length.
+        */
+       switch (Id) {
+
+       case OID_SKGE_DIAG_MODE:
+               if (*pLen < sizeof(SK_U32)) {
+
+                       *pLen = sizeof(SK_U32);
+                       return (SK_PNMI_ERR_TOO_SHORT);
+               }
+               break;
+
+       default:
+               SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR040, SK_PNMI_ERR040MSG);
+               *pLen = 0;
+               return (SK_PNMI_ERR_GENERAL);
+       }
+
+       /* Perform action. */
+
+       /* GET value. */
+       if (Action == SK_PNMI_GET) {
+
+               switch (Id) {
+
+               case OID_SKGE_DIAG_MODE:
+                       DiagStatus = pAC->Pnmi.DiagAttached;
+                       SK_PNMI_STORE_U32(pBuf, DiagStatus);
+                       *pLen = sizeof(SK_U32); 
+                       RetCode = SK_PNMI_ERR_OK;
+                       break;
+
+               default:
+                       *pLen = 0;      
+                       RetCode = SK_PNMI_ERR_GENERAL;
+                       break;
+               }
+               return (RetCode); 
+       }
+
+       /* From here SET or PRESET value. */
+       
+       /* PRESET value is not supported. */
+       if (Action == SK_PNMI_PRESET) {
+               return (SK_PNMI_ERR_OK); 
+       }
+
+       /* SET value. */
+       switch (Id) {
+               case OID_SKGE_DIAG_MODE:
+
+                       /* Handle the SET. */
+                       switch (*pBuf) {
+
+                               /* Attach the DIAG to this adapter. */
+                               case SK_DIAG_ATTACHED:
+                                       /* Check if we come from running */
+                                       if (pAC->Pnmi.DiagAttached == SK_DIAG_RUNNING) {
+
+                                               RetCode = SkDrvLeaveDiagMode(pAC);
+
+                                       }
+                                       else if (pAC->Pnmi.DiagAttached == SK_DIAG_IDLE) {
+
+                                               RetCode = SK_PNMI_ERR_OK;
+                                       }       
+                                       
+                                       else {
+
+                                               RetCode = SK_PNMI_ERR_GENERAL;
+
+                                       }
+                                       
+                                       if (RetCode == SK_PNMI_ERR_OK) {
+
+                                               pAC->Pnmi.DiagAttached = SK_DIAG_ATTACHED;
+                                       }
+                                       break;
+
+                               /* Enter the DIAG mode in the driver. */
+                               case SK_DIAG_RUNNING:
+                                       RetCode = SK_PNMI_ERR_OK;
+                                       
+                                       /*
+                                        * If DiagAttached is set, we can tell the driver
+                                        * to enter the DIAG mode.
+                                        */
+                                       if (pAC->Pnmi.DiagAttached == SK_DIAG_ATTACHED) {
+                                               /* If DiagMode is not active, we can enter it. */
+                                               if (!pAC->DiagModeActive) {
+
+                                                       RetCode = SkDrvEnterDiagMode(pAC); 
+                                               }
+                                               else {
+
+                                                       RetCode = SK_PNMI_ERR_GENERAL;
+                                               }
+                                       }
+                                       else {
+
+                                               RetCode = SK_PNMI_ERR_GENERAL;
+                                       }
+                                       
+                                       if (RetCode == SK_PNMI_ERR_OK) {
+
+                                               pAC->Pnmi.DiagAttached = SK_DIAG_RUNNING;
+                                       }
+                                       break;
+
+                               case SK_DIAG_IDLE:
+                                       /* Check if we come from running */
+                                       if (pAC->Pnmi.DiagAttached == SK_DIAG_RUNNING) {
+
+                                               RetCode = SkDrvLeaveDiagMode(pAC);
+
+                                       }
+                                       else if (pAC->Pnmi.DiagAttached == SK_DIAG_ATTACHED) {
+
+                                               RetCode = SK_PNMI_ERR_OK;
+                                       }       
+                                       
+                                       else {
+
+                                               RetCode = SK_PNMI_ERR_GENERAL;
+
+                                       }
+
+                                       if (RetCode == SK_PNMI_ERR_OK) {
+
+                                               pAC->Pnmi.DiagAttached = SK_DIAG_IDLE;
+                                       }
+                                       break;
+
+                               default:
+                                       RetCode = SK_PNMI_ERR_BAD_VALUE;
+                                       break;
+                       }
+                       break;
+
+               default:
+                       RetCode = SK_PNMI_ERR_GENERAL;
+       }
+
+       if (RetCode == SK_PNMI_ERR_OK) {
+               *pLen = sizeof(SK_U32);
+       }
+       else {
+
+               *pLen = 0;
+       }
+       return (RetCode);
+}
+#endif /* SK_DIAG_SUPPORT */
+
+/*****************************************************************************
+ *
+ * Vct - OID handler function of  OIDs
+ *
+ * Description:
+ *     The code is simple. No description necessary.
+ *
+ * Returns:
+ *     SK_PNMI_ERR_OK           The request was performed successfully.
+ *     SK_PNMI_ERR_GENERAL      A general severe internal error occured.
+ *     SK_PNMI_ERR_TOO_SHORT    The passed buffer is too short to contain
+ *                              the correct data (e.g. a 32bit value is
+ *                              needed, but a 16 bit value was passed).
+ *     SK_PNMI_ERR_UNKNOWN_INST The requested instance of the OID doesn't
+ *                           exist (e.g. port instance 3 on a two port
+ *                              adapter).
+ *     SK_PNMI_ERR_READ_ONLY    Only the Get action is allowed.
+ *
+ */
+
+PNMI_STATIC int Vct(
+SK_AC *pAC,            /* Pointer to adapter context */
+SK_IOC IoC,            /* IO context handle */
+int Action,            /* GET/PRESET/SET action */
+SK_U32 Id,             /* Object ID that is to be processed */
+char *pBuf,            /* Buffer used for the management data transfer */
+unsigned int *pLen,    /* On call: pBuf buffer length. On return: used buffer */
+SK_U32 Instance,       /* Instance (-1,2..n) that is to be queried */
+unsigned int TableIndex, /* Index to the Id table */
+SK_U32 NetIndex)       /* NetIndex (0..n), in single net mode always zero */
+{
+       SK_GEPORT       *pPrt;
+       SK_PNMI_VCT     *pVctBackupData;
+       SK_U32          LogPortMax;
+       SK_U32          PhysPortMax;
+       SK_U32          PhysPortIndex;
+       SK_U32          Limit;
+       SK_U32          Offset;
+       SK_BOOL         Link;
+       SK_U32          RetCode = SK_PNMI_ERR_GENERAL;
+       int             i;
+       SK_EVPARA       Para;
+       SK_U32          CableLength;
+       
+       /*
+        * Calculate the port indexes from the instance.
+        */
+       PhysPortMax = pAC->GIni.GIMacsFound;
+       LogPortMax = SK_PNMI_PORT_PHYS2LOG(PhysPortMax);
+       
+       /* Dual net mode? */
+       if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) {
+               LogPortMax--;
+       }
+       
+       if ((Instance != (SK_U32) (-1))) {
+               /* Check instance range. */
+               if ((Instance < 2) || (Instance > LogPortMax)) {
+                       *pLen = 0;
+                       return (SK_PNMI_ERR_UNKNOWN_INST);
+               }
+               
+               if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) {
+                       PhysPortIndex = NetIndex;
+               }
+               else {
+                       PhysPortIndex = Instance - 2;
+               }
+               Limit = PhysPortIndex + 1;
+       }
+       else {
+               /*
+                * Instance == (SK_U32) (-1), get all Instances of that OID.
+                *
+                * Not implemented yet. May be used in future releases.
+                */
+               PhysPortIndex = 0;
+               Limit = PhysPortMax;
+       }
+       
+       pPrt = &pAC->GIni.GP[PhysPortIndex];
+       if (pPrt->PHWLinkUp) {
+               Link = SK_TRUE;
+       }
+       else {
+               Link = SK_FALSE;
+       }
+       
+       /* Check MAC type */
+       if (pPrt->PhyType != SK_PHY_MARV_COPPER) {
+               *pLen = 0;
+               return (SK_PNMI_ERR_GENERAL);
+       }
+       
+       /* Initialize backup data pointer. */
+       pVctBackupData = &pAC->Pnmi.VctBackup[PhysPortIndex];
+       
+       /* Check action type */
+       if (Action == SK_PNMI_GET) {
+               /* Check length */
+               switch (Id) {
+               
+               case OID_SKGE_VCT_GET:
+                       if (*pLen < (Limit - PhysPortIndex) * sizeof(SK_PNMI_VCT)) {
+                               *pLen = (Limit - PhysPortIndex) * sizeof(SK_PNMI_VCT);
+                               return (SK_PNMI_ERR_TOO_SHORT);
+                       }
+                       break;
+               
+               case OID_SKGE_VCT_STATUS:
+                       if (*pLen < (Limit - PhysPortIndex) * sizeof(SK_U8)) {
+                               *pLen = (Limit - PhysPortIndex) * sizeof(SK_U8);
+                               return (SK_PNMI_ERR_TOO_SHORT);
+                       }
+                       break;
+               
+               default:
+                       *pLen = 0;
+                       return (SK_PNMI_ERR_GENERAL);
+               }       
+               
+               /* Get value */
+               Offset = 0;
+               for (; PhysPortIndex < Limit; PhysPortIndex++) {
+                       switch (Id) {
+                       
+                       case OID_SKGE_VCT_GET:
+                               if ((Link == SK_FALSE) &&
+                                       (pAC->Pnmi.VctStatus[PhysPortIndex] & SK_PNMI_VCT_PENDING)) {
+                                       RetCode = SkGmCableDiagStatus(pAC, IoC, PhysPortIndex, SK_FALSE);
+                                       if (RetCode == 0) {
+                                               pAC->Pnmi.VctStatus[PhysPortIndex] &= ~SK_PNMI_VCT_PENDING;
+                                               pAC->Pnmi.VctStatus[PhysPortIndex] |=
+                                                       (SK_PNMI_VCT_NEW_VCT_DATA | SK_PNMI_VCT_TEST_DONE);
+                                               
+                                               /* Copy results for later use to PNMI struct. */
+                                               for (i = 0; i < 4; i++)  {
+                                                       if (pPrt->PMdiPairSts[i] == SK_PNMI_VCT_NORMAL_CABLE) {
+                                                               if ((pPrt->PMdiPairLen[i] > 35) && (pPrt->PMdiPairLen[i] < 0xff)) {
+                                                                       pPrt->PMdiPairSts[i] = SK_PNMI_VCT_IMPEDANCE_MISMATCH;
+                                                               }
+                                                       }
+                                                       if ((pPrt->PMdiPairLen[i] > 35) && (pPrt->PMdiPairLen[i] != 0xff)) {
+                                                               CableLength = 1000 * (((175 * pPrt->PMdiPairLen[i]) / 210) - 28);
+                                                       }
+                                                       else {
+                                                               CableLength = 0;
+                                                       }
+                                                       pVctBackupData->PMdiPairLen[i] = CableLength;
+                                                       pVctBackupData->PMdiPairSts[i] = pPrt->PMdiPairSts[i];
+                                               }
+
+                                               Para.Para32[0] = PhysPortIndex;
+                                               Para.Para32[1] = -1;
+                                               SkEventQueue(pAC, SKGE_DRV, SK_DRV_PORT_RESET, Para);
+                                               SkEventDispatcher(pAC, IoC);
+                                       }
+                                       else {
+                                               ; /* VCT test is running. */
+                                       }
+                               }
+                               
+                               /* Get all results. */
+                               CheckVctStatus(pAC, IoC, pBuf, Offset, PhysPortIndex);
+                               Offset += sizeof(SK_U8);
+                               *(pBuf + Offset) = pPrt->PCableLen;
+                               Offset += sizeof(SK_U8);
+                               for (i = 0; i < 4; i++)  {
+                                       SK_PNMI_STORE_U32((pBuf + Offset), pVctBackupData->PMdiPairLen[i]);
+                                       Offset += sizeof(SK_U32);
+                               }
+                               for (i = 0; i < 4; i++)  {
+                                       *(pBuf + Offset) = pVctBackupData->PMdiPairSts[i];
+                                       Offset += sizeof(SK_U8);
+                               }
+                               
+                               RetCode = SK_PNMI_ERR_OK;
+                               break;
+               
+                       case OID_SKGE_VCT_STATUS:
+                               CheckVctStatus(pAC, IoC, pBuf, Offset, PhysPortIndex);
+                               Offset += sizeof(SK_U8);
+                               RetCode = SK_PNMI_ERR_OK;
+                               break;
+                       
+                       default:
+                               *pLen = 0;
+                               return (SK_PNMI_ERR_GENERAL);
+                       }
+               } /* for */
+               *pLen = Offset;
+               return (RetCode);
+       
+       } /* if SK_PNMI_GET */
+       
+       /*
+        * From here SET or PRESET action. Check if the passed
+        * buffer length is plausible.
+        */
+       
+       /* Check length */
+       switch (Id) {
+       case OID_SKGE_VCT_SET:
+               if (*pLen < (Limit - PhysPortIndex) * sizeof(SK_U32)) {
+                       *pLen = (Limit - PhysPortIndex) * sizeof(SK_U32);
+                       return (SK_PNMI_ERR_TOO_SHORT);
+               }
+               break;
+       
+       default:
+               *pLen = 0;
+               return (SK_PNMI_ERR_GENERAL);
+       }
+       
+       /*
+        * Perform preset or set.
+        */
+       
+       /* VCT does not support PRESET action. */
+       if (Action == SK_PNMI_PRESET) {
+               return (SK_PNMI_ERR_OK);
+       }
+       
+       Offset = 0;
+       for (; PhysPortIndex < Limit; PhysPortIndex++) {
+               switch (Id) {
+               case OID_SKGE_VCT_SET: /* Start VCT test. */
+                       if (Link == SK_FALSE) {
+                               SkGeStopPort(pAC, IoC, PhysPortIndex, SK_STOP_ALL, SK_SOFT_RST);
+                               
+                               RetCode = SkGmCableDiagStatus(pAC, IoC, PhysPortIndex, SK_TRUE);
+                               if (RetCode == 0) { /* RetCode: 0 => Start! */
+                                       pAC->Pnmi.VctStatus[PhysPortIndex] |= SK_PNMI_VCT_PENDING;
+                                       pAC->Pnmi.VctStatus[PhysPortIndex] &= ~SK_PNMI_VCT_NEW_VCT_DATA;
+                                       pAC->Pnmi.VctStatus[PhysPortIndex] &= ~SK_PNMI_VCT_LINK;
+                                       
+                                       /*
+                                        * Start VCT timer counter.
+                                        */
+                                       SK_MEMSET((char *) &Para, 0, sizeof(Para));
+                                       Para.Para32[0] = PhysPortIndex;
+                                       Para.Para32[1] = -1;
+                                       SkTimerStart(pAC, IoC, &pAC->Pnmi.VctTimeout[PhysPortIndex].VctTimer,
+                                               4000000, SKGE_PNMI, SK_PNMI_EVT_VCT_RESET, Para);
+                                       SK_PNMI_STORE_U32((pBuf + Offset), RetCode);
+                                       RetCode = SK_PNMI_ERR_OK;
+                               }
+                               else { /* RetCode: 2 => Running! */
+                                       SK_PNMI_STORE_U32((pBuf + Offset), RetCode);
+                                       RetCode = SK_PNMI_ERR_OK;
+                               }
+                       }
+                       else { /* RetCode: 4 => Link! */
+                               RetCode = 4;
+                               SK_PNMI_STORE_U32((pBuf + Offset), RetCode);
+                               RetCode = SK_PNMI_ERR_OK;
+                       }
+                       Offset += sizeof(SK_U32);
+                       break;
+       
+               default:
+                       *pLen = 0;
+                       return (SK_PNMI_ERR_GENERAL);
+               }
+       } /* for */
+       *pLen = Offset;
+       return (RetCode);
+
+} /* Vct */
+
+
+PNMI_STATIC void CheckVctStatus(
+SK_AC          *pAC,
+SK_IOC         IoC,
+char           *pBuf,
+SK_U32         Offset,
+SK_U32         PhysPortIndex)
+{
+       SK_GEPORT       *pPrt;
+       SK_PNMI_VCT     *pVctData;
+       SK_U32          RetCode;
+       
+       pPrt = &pAC->GIni.GP[PhysPortIndex];
+       
+       pVctData = (SK_PNMI_VCT *) (pBuf + Offset);
+       pVctData->VctStatus = SK_PNMI_VCT_NONE;
+       
+       if (!pPrt->PHWLinkUp) {
+               
+               /* Was a VCT test ever made before? */
+               if (pAC->Pnmi.VctStatus[PhysPortIndex] & SK_PNMI_VCT_TEST_DONE) {
+                       if ((pAC->Pnmi.VctStatus[PhysPortIndex] & SK_PNMI_VCT_LINK)) {
+                               pVctData->VctStatus |= SK_PNMI_VCT_OLD_VCT_DATA;
+                       }
+                       else {
+                               pVctData->VctStatus |= SK_PNMI_VCT_NEW_VCT_DATA;
+                       }
+               }
+               
+               /* Check VCT test status. */
+               RetCode = SkGmCableDiagStatus(pAC,IoC, PhysPortIndex, SK_FALSE);
+               if (RetCode == 2) { /* VCT test is running. */
+                       pVctData->VctStatus |= SK_PNMI_VCT_RUNNING;
+               }
+               else { /* VCT data was copied to pAC here. Check PENDING state. */
+                       if (pAC->Pnmi.VctStatus[PhysPortIndex] & SK_PNMI_VCT_PENDING) {
+                               pVctData->VctStatus |= SK_PNMI_VCT_NEW_VCT_DATA;
+                       }
+               }
+               
+               if (pPrt->PCableLen != 0xff) { /* Old DSP value. */
+                       pVctData->VctStatus |= SK_PNMI_VCT_OLD_DSP_DATA;
+               }
+       }
+       else {
+               
+               /* Was a VCT test ever made before? */
+               if (pAC->Pnmi.VctStatus[PhysPortIndex] & SK_PNMI_VCT_TEST_DONE) {
+                       pVctData->VctStatus &= ~SK_PNMI_VCT_NEW_VCT_DATA;
+                       pVctData->VctStatus |= SK_PNMI_VCT_OLD_VCT_DATA;
+               }
+               
+               /* DSP only valid in 100/1000 modes. */
+               if (pAC->GIni.GP[PhysPortIndex].PLinkSpeedUsed !=
+                       SK_LSPEED_STAT_10MBPS) {        
+                       pVctData->VctStatus |= SK_PNMI_VCT_NEW_DSP_DATA;
+               }
+       }
+} /* CheckVctStatus */
+
+
+/*****************************************************************************
+ *
+ *      SkPnmiGenIoctl - Handles new generic PNMI IOCTL, calls the needed
+ *                       PNMI function depending on the subcommand and
+ *                       returns all data belonging to the complete database
+ *                       or OID request.
+ *
+ * Description:
+ *     Looks up the requested subcommand, calls the corresponding handler
+ *     function and passes all required parameters to it.
+ *     The function is called by the driver. It is needed to handle the new
+ *  generic PNMI IOCTL. This IOCTL is given to the driver and contains both
+ *  the OID and a subcommand to decide what kind of request has to be done.
+ *
+ * Returns:
+ *     SK_PNMI_ERR_OK           The request was successfully performed
+ *     SK_PNMI_ERR_GENERAL      A general severe internal error occured
+ *     SK_PNMI_ERR_TOO_SHORT    The passed buffer is too short to take
+ *                              the data.
+ *     SK_PNMI_ERR_UNKNOWN_OID  The requested OID is unknown
+ *     SK_PNMI_ERR_UNKNOWN_INST The requested instance of the OID doesn't
+ *                           exist (e.g. port instance 3 on a two port
+ *                              adapter.
+ */
+int SkPnmiGenIoctl(
+SK_AC          *pAC,           /* Pointer to adapter context struct */
+SK_IOC         IoC,            /* I/O context */
+void           *pBuf,          /* Buffer used for the management data transfer */
+unsigned int *pLen,            /* Length of buffer */
+SK_U32         NetIndex)       /* NetIndex (0..n), in single net mode always zero */
+{
+SK_I32 Mode;                   /* Store value of subcommand. */
+SK_U32 Oid;                    /* Store value of OID. */
+int            ReturnCode;             /* Store return value to show status of PNMI action. */
+int    HeaderLength;   /* Length of desired action plus OID. */
+
+       ReturnCode = SK_PNMI_ERR_GENERAL;
+       
+       SK_MEMCPY(&Mode, pBuf, sizeof(SK_I32));
+       SK_MEMCPY(&Oid, (char *) pBuf + sizeof(SK_I32), sizeof(SK_U32));
+       HeaderLength = sizeof(SK_I32) + sizeof(SK_U32);
+       *pLen = *pLen - HeaderLength;
+       SK_MEMCPY((char *) pBuf + sizeof(SK_I32), (char *) pBuf + HeaderLength, *pLen);
+       
+       switch(Mode) {
+       case SK_GET_SINGLE_VAR:
+               ReturnCode = SkPnmiGetVar(pAC, IoC, Oid, 
+                               (char *) pBuf + sizeof(SK_I32), pLen,
+                               ((SK_U32) (-1)), NetIndex);
+               SK_PNMI_STORE_U32(pBuf, ReturnCode);
+               *pLen = *pLen + sizeof(SK_I32);
+               break;
+       case SK_PRESET_SINGLE_VAR:
+               ReturnCode = SkPnmiPreSetVar(pAC, IoC, Oid, 
+                               (char *) pBuf + sizeof(SK_I32), pLen,
+                               ((SK_U32) (-1)), NetIndex);
+               SK_PNMI_STORE_U32(pBuf, ReturnCode);
+               *pLen = *pLen + sizeof(SK_I32);
+               break;
+       case SK_SET_SINGLE_VAR:
+               ReturnCode = SkPnmiSetVar(pAC, IoC, Oid, 
+                               (char *) pBuf + sizeof(SK_I32), pLen,
+                               ((SK_U32) (-1)), NetIndex);
+               SK_PNMI_STORE_U32(pBuf, ReturnCode);
+               *pLen = *pLen + sizeof(SK_I32);
+               break;
+       case SK_GET_FULL_MIB:
+               ReturnCode = SkPnmiGetStruct(pAC, IoC, pBuf, pLen, NetIndex);
+               break;
+       case SK_PRESET_FULL_MIB:
+               ReturnCode = SkPnmiPreSetStruct(pAC, IoC, pBuf, pLen, NetIndex);
+               break;
+       case SK_SET_FULL_MIB:
+               ReturnCode = SkPnmiSetStruct(pAC, IoC, pBuf, pLen, NetIndex);
+               break;
+       default:
+               break;
+       }
+       
+       return (ReturnCode);
+
+} /* SkGeIocGen */
diff --git a/drivers/net/sk98lin/skgesirq.c b/drivers/net/sk98lin/skgesirq.c
new file mode 100644 (file)
index 0000000..3e7aa49
--- /dev/null
@@ -0,0 +1,2229 @@
+/******************************************************************************
+ *
+ * Name:       skgesirq.c
+ * Project:    Gigabit Ethernet Adapters, Common Modules
+ * Version:    $Revision: 1.92 $
+ * Date:       $Date: 2003/09/16 14:37:07 $
+ * Purpose:    Special IRQ module
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *     (C)Copyright 1998-2002 SysKonnect.
+ *     (C)Copyright 2002-2003 Marvell.
+ *
+ *     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.
+ *
+ *     The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/*
+ *     Special Interrupt handler
+ *
+ *     The following abstract should show how this module is included
+ *     in the driver path:
+ *
+ *     In the ISR of the driver the bits for frame transmission complete and
+ *     for receive complete are checked and handled by the driver itself.
+ *     The bits of the slow path mask are checked after that and then the
+ *     entry into the so-called "slow path" is prepared. It is an implementors
+ *     decision whether this is executed directly or just scheduled by
+ *     disabling the mask. In the interrupt service routine some events may be
+ *     generated, so it would be a good idea to call the EventDispatcher
+ *     right after this ISR.
+ *
+ *     The Interrupt source register of the adapter is NOT read by this module.
+ *  SO if the drivers implementor needs a while loop around the
+ *     slow data paths interrupt bits, he needs to call the SkGeSirqIsr() for
+ *     each loop entered.
+ *
+ *     However, the MAC Interrupt status registers are read in a while loop.
+ *
+ */
+
+#if (defined(DEBUG) || ((!defined(LINT)) && (!defined(SK_SLIM))))
+static const char SysKonnectFileId[] =
+       "@(#) $Id: skgesirq.c,v 1.92 2003/09/16 14:37:07 rschmidt Exp $ (C) Marvell.";
+#endif
+
+#include "h/skdrv1st.h"                /* Driver Specific Definitions */
+#ifndef SK_SLIM
+#include "h/skgepnmi.h"                /* PNMI Definitions */
+#include "h/skrlmt.h"          /* RLMT Definitions */
+#endif
+#include "h/skdrv2nd.h"                /* Adapter Control and Driver specific Def. */
+
+/* local function prototypes */
+#ifdef GENESIS
+static int     SkGePortCheckUpXmac(SK_AC*, SK_IOC, int, SK_BOOL);
+static int     SkGePortCheckUpBcom(SK_AC*, SK_IOC, int, SK_BOOL);
+static void    SkPhyIsrBcom(SK_AC*, SK_IOC, int, SK_U16);
+#endif /* GENESIS */
+#ifdef YUKON
+static int     SkGePortCheckUpGmac(SK_AC*, SK_IOC, int, SK_BOOL);
+static void    SkPhyIsrGmac(SK_AC*, SK_IOC, int, SK_U16);
+#endif /* YUKON */
+#ifdef OTHER_PHY
+static int     SkGePortCheckUpLone(SK_AC*, SK_IOC, int, SK_BOOL);
+static int     SkGePortCheckUpNat(SK_AC*, SK_IOC, int, SK_BOOL);
+static void    SkPhyIsrLone(SK_AC*, SK_IOC, int, SK_U16);
+#endif /* OTHER_PHY */
+
+#ifdef GENESIS
+/*
+ * array of Rx counter from XMAC which are checked
+ * in AutoSense mode to check whether a link is not able to auto-negotiate.
+ */
+static const SK_U16 SkGeRxRegs[]= {
+       XM_RXF_64B,
+       XM_RXF_127B,
+       XM_RXF_255B,
+       XM_RXF_511B,
+       XM_RXF_1023B,
+       XM_RXF_MAX_SZ
+} ;
+#endif /* GENESIS */
+
+#ifdef __C2MAN__
+/*
+ *     Special IRQ function
+ *
+ *     General Description:
+ *
+ */
+intro()
+{}
+#endif
+
+/******************************************************************************
+ *
+ *     SkHWInitDefSense() - Default Autosensing mode initialization
+ *
+ * Description: sets the PLinkMode for HWInit
+ *
+ * Returns: N/A
+ */
+static void SkHWInitDefSense(
+SK_AC  *pAC,   /* adapter context */
+SK_IOC IoC,    /* IO context */
+int            Port)   /* Port Index (MAC_1 + n) */
+{
+       SK_GEPORT       *pPrt;          /* GIni Port struct pointer */
+
+       pPrt = &pAC->GIni.GP[Port];
+
+       pPrt->PAutoNegTimeOut = 0;
+
+       if (pPrt->PLinkModeConf != SK_LMODE_AUTOSENSE) {
+               pPrt->PLinkMode = pPrt->PLinkModeConf;
+               return;
+       }
+
+       SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ,
+               ("AutoSensing: First mode %d on Port %d\n",
+               (int)SK_LMODE_AUTOFULL, Port));
+
+       pPrt->PLinkMode = (SK_U8)SK_LMODE_AUTOFULL;
+
+       return;
+}      /* SkHWInitDefSense */
+
+
+#ifdef GENESIS
+/******************************************************************************
+ *
+ *     SkHWSenseGetNext() - Get Next Autosensing Mode
+ *
+ * Description: gets the appropriate next mode
+ *
+ * Note:
+ *
+ */
+static SK_U8 SkHWSenseGetNext(
+SK_AC  *pAC,   /* adapter context */
+SK_IOC IoC,    /* IO context */
+int            Port)   /* Port Index (MAC_1 + n) */
+{
+       SK_GEPORT       *pPrt;          /* GIni Port struct pointer */
+
+       pPrt = &pAC->GIni.GP[Port];
+
+       pPrt->PAutoNegTimeOut = 0;
+
+    if (pPrt->PLinkModeConf != (SK_U8)SK_LMODE_AUTOSENSE) {
+               /* Leave all as configured */
+               return(pPrt->PLinkModeConf);
+       }
+
+    if (pPrt->PLinkMode == (SK_U8)SK_LMODE_AUTOFULL) {
+               /* Return next mode AUTOBOTH */
+        return ((SK_U8)SK_LMODE_AUTOBOTH);
+       }
+
+       /* Return default autofull */
+    return ((SK_U8)SK_LMODE_AUTOFULL);
+}      /* SkHWSenseGetNext */
+
+
+/******************************************************************************
+ *
+ *     SkHWSenseSetNext() - Autosensing Set next mode
+ *
+ * Description:        sets the appropriate next mode
+ *
+ * Returns: N/A
+ */
+static void SkHWSenseSetNext(
+SK_AC  *pAC,           /* adapter context */
+SK_IOC IoC,            /* IO context */
+int            Port,           /* Port Index (MAC_1 + n) */
+SK_U8  NewMode)        /* New Mode to be written in sense mode */
+{
+       SK_GEPORT       *pPrt;          /* GIni Port struct pointer */
+
+       pPrt = &pAC->GIni.GP[Port];
+
+       pPrt->PAutoNegTimeOut = 0;
+
+    if (pPrt->PLinkModeConf != (SK_U8)SK_LMODE_AUTOSENSE) {
+               return;
+       }
+
+       SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ,
+               ("AutoSensing: next mode %d on Port %d\n",
+               (int)NewMode, Port));
+
+       pPrt->PLinkMode = NewMode;
+
+       return;
+}      /* SkHWSenseSetNext */
+#endif /* GENESIS */
+
+
+/******************************************************************************
+ *
+ *     SkHWLinkDown() - Link Down handling
+ *
+ * Description: handles the hardware link down signal
+ *
+ * Returns: N/A
+ */
+void SkHWLinkDown(
+SK_AC  *pAC,           /* adapter context */
+SK_IOC IoC,            /* IO context */
+int            Port)           /* Port Index (MAC_1 + n) */
+{
+       SK_GEPORT       *pPrt;          /* GIni Port struct pointer */
+
+       pPrt = &pAC->GIni.GP[Port];
+
+       /* Disable all MAC interrupts */
+       SkMacIrqDisable(pAC, IoC, Port);
+
+       /* Disable Receiver and Transmitter */
+       SkMacRxTxDisable(pAC, IoC, Port);
+       
+       /* Init default sense mode */
+       SkHWInitDefSense(pAC, IoC, Port);
+
+       if (pPrt->PHWLinkUp == SK_FALSE) {
+               return;
+       }
+
+       SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ,
+               ("Link down Port %d\n", Port));
+
+       /* Set Link to DOWN */
+       pPrt->PHWLinkUp = SK_FALSE;
+
+       /* Reset Port stati */
+    pPrt->PLinkModeStatus = (SK_U8)SK_LMODE_STAT_UNKNOWN;
+    pPrt->PFlowCtrlStatus = (SK_U8)SK_FLOW_STAT_NONE;
+       pPrt->PLinkSpeedUsed = (SK_U8)SK_LSPEED_STAT_INDETERMINATED;
+
+       /* Re-init Phy especially when the AutoSense default is set now */
+       SkMacInitPhy(pAC, IoC, Port, SK_FALSE);
+
+       /* GP0: used for workaround of Rev. C Errata 2 */
+
+       /* Do NOT signal to RLMT */
+
+       /* Do NOT start the timer here */
+}      /* SkHWLinkDown */
+
+
+/******************************************************************************
+ *
+ *     SkHWLinkUp() - Link Up handling
+ *
+ * Description: handles the hardware link up signal
+ *
+ * Returns: N/A
+ */
+static void SkHWLinkUp(
+SK_AC  *pAC,   /* adapter context */
+SK_IOC IoC,    /* IO context */
+int            Port)   /* Port Index (MAC_1 + n) */
+{
+       SK_GEPORT       *pPrt;          /* GIni Port struct pointer */
+
+       pPrt = &pAC->GIni.GP[Port];
+
+       if (pPrt->PHWLinkUp) {
+               /* We do NOT need to proceed on active link */
+               return;
+       }
+
+       pPrt->PHWLinkUp = SK_TRUE;
+       pPrt->PAutoNegFail = SK_FALSE;
+    pPrt->PLinkModeStatus = (SK_U8)SK_LMODE_STAT_UNKNOWN;
+
+    if (pPrt->PLinkMode != (SK_U8)SK_LMODE_AUTOHALF &&
+        pPrt->PLinkMode != (SK_U8)SK_LMODE_AUTOFULL &&
+        pPrt->PLinkMode != (SK_U8)SK_LMODE_AUTOBOTH) {
+               /* Link is up and no Auto-negotiation should be done */
+
+               /* Link speed should be the configured one */
+               switch (pPrt->PLinkSpeed) {
+               case SK_LSPEED_AUTO:
+                       /* default is 1000 Mbps */
+               case SK_LSPEED_1000MBPS:
+                       pPrt->PLinkSpeedUsed = (SK_U8)SK_LSPEED_STAT_1000MBPS;
+                       break;
+               case SK_LSPEED_100MBPS:
+                       pPrt->PLinkSpeedUsed = (SK_U8)SK_LSPEED_STAT_100MBPS;
+                       break;
+               case SK_LSPEED_10MBPS:
+                       pPrt->PLinkSpeedUsed = (SK_U8)SK_LSPEED_STAT_10MBPS;
+                       break;
+               }
+
+               /* Set Link Mode Status */
+               if (pPrt->PLinkMode == SK_LMODE_FULL) {
+                       pPrt->PLinkModeStatus = (SK_U8)SK_LMODE_STAT_FULL;
+               }
+               else {
+            pPrt->PLinkModeStatus = (SK_U8)SK_LMODE_STAT_HALF;
+               }
+
+               /* No flow control without auto-negotiation */
+        pPrt->PFlowCtrlStatus = (SK_U8)SK_FLOW_STAT_NONE;
+
+               /* enable Rx/Tx */
+        (void)SkMacRxTxEnable(pAC, IoC, Port);
+       }
+}      /* SkHWLinkUp */
+
+
+/******************************************************************************
+ *
+ *     SkMacParity() - MAC parity workaround
+ *
+ * Description: handles MAC parity errors correctly
+ *
+ * Returns: N/A
+ */
+static void SkMacParity(
+SK_AC  *pAC,   /* adapter context */
+SK_IOC IoC,    /* IO context */
+int            Port)   /* Port Index of the port failed */
+{
+       SK_EVPARA       Para;
+       SK_GEPORT       *pPrt;          /* GIni Port struct pointer */
+       SK_U32          TxMax;          /* Tx Max Size Counter */
+
+       pPrt = &pAC->GIni.GP[Port];
+
+       /* Clear IRQ Tx Parity Error */
+#ifdef GENESIS
+       if (pAC->GIni.GIGenesis) {
+
+               SK_OUT16(IoC, MR_ADDR(Port, TX_MFF_CTRL1), MFF_CLR_PERR);
+       }
+#endif /* GENESIS */
+       
+#ifdef YUKON
+       if (pAC->GIni.GIYukon) {
+               /* HW-Bug #8: cleared by GMF_CLI_TX_FC instead of GMF_CLI_TX_PE */
+               SK_OUT8(IoC, MR_ADDR(Port, TX_GMF_CTRL_T),
+                       (SK_U8)((pAC->GIni.GIChipId == CHIP_ID_YUKON &&
+                       pAC->GIni.GIChipRev == 0) ? GMF_CLI_TX_FC : GMF_CLI_TX_PE));
+       }
+#endif /* YUKON */
+       
+       if (pPrt->PCheckPar) {
+
+               if (Port == MAC_1) {
+                       SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_SIRQ_E016, SKERR_SIRQ_E016MSG);
+               }
+               else {
+                       SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_SIRQ_E017, SKERR_SIRQ_E017MSG);
+               }
+               Para.Para64 = Port;
+               SkEventQueue(pAC, SKGE_DRV, SK_DRV_PORT_FAIL, Para);
+               
+               Para.Para32[0] = Port;
+               SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_LINK_DOWN, Para);
+
+               return;
+       }
+
+       /* Check whether frames with a size of 1k were sent */
+#ifdef GENESIS
+       if (pAC->GIni.GIGenesis) {
+               /* Snap statistic counters */
+               (void)SkXmUpdateStats(pAC, IoC, Port);
+               
+               (void)SkXmMacStatistic(pAC, IoC, Port, XM_TXF_MAX_SZ, &TxMax);
+       }
+#endif /* GENESIS */
+       
+#ifdef YUKON
+       if (pAC->GIni.GIYukon) {
+
+               (void)SkGmMacStatistic(pAC, IoC, Port, GM_TXF_1518B, &TxMax);
+       }
+#endif /* YUKON */
+       
+       if (TxMax > 0) {
+               /* From now on check the parity */
+               pPrt->PCheckPar = SK_TRUE;
+       }
+}      /* SkMacParity */
+
+
+/******************************************************************************
+ *
+ *     SkGeHwErr() - Hardware Error service routine
+ *
+ * Description: handles all HW Error interrupts
+ *
+ * Returns: N/A
+ */
+static void SkGeHwErr(
+SK_AC  *pAC,           /* adapter context */
+SK_IOC IoC,            /* IO context */
+SK_U32 HwStatus)       /* Interrupt status word */
+{
+       SK_EVPARA       Para;
+       SK_U16          Word;
+
+       if ((HwStatus & (IS_IRQ_MST_ERR | IS_IRQ_STAT)) != 0) {
+               /* PCI Errors occured */
+               if ((HwStatus & IS_IRQ_STAT) != 0) {
+                       SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_SIRQ_E013, SKERR_SIRQ_E013MSG);
+               }
+               else {
+                       SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_SIRQ_E012, SKERR_SIRQ_E012MSG);
+               }
+
+               /* Reset all bits in the PCI STATUS register */
+               SK_IN16(IoC, PCI_C(PCI_STATUS), &Word);
+               
+               SK_OUT8(IoC, B2_TST_CTRL1, TST_CFG_WRITE_ON);
+        SK_OUT16(IoC, PCI_C(PCI_STATUS), (SK_U16)(Word | PCI_ERRBITS));
+               SK_OUT8(IoC, B2_TST_CTRL1, TST_CFG_WRITE_OFF);
+
+               Para.Para64 = 0;
+               SkEventQueue(pAC, SKGE_DRV, SK_DRV_ADAP_FAIL, Para);
+       }
+
+#ifdef GENESIS
+       if (pAC->GIni.GIGenesis) {
+
+               if ((HwStatus & IS_NO_STAT_M1) != 0) {
+                       /* Ignore it */
+                       /* This situation is also indicated in the descriptor */
+                       SK_OUT16(IoC, MR_ADDR(MAC_1, RX_MFF_CTRL1), MFF_CLR_INSTAT);
+               }
+
+               if ((HwStatus & IS_NO_STAT_M2) != 0) {
+                       /* Ignore it */
+                       /* This situation is also indicated in the descriptor */
+                       SK_OUT16(IoC, MR_ADDR(MAC_2, RX_MFF_CTRL1), MFF_CLR_INSTAT);
+               }
+
+               if ((HwStatus & IS_NO_TIST_M1) != 0) {
+                       /* Ignore it */
+                       /* This situation is also indicated in the descriptor */
+                       SK_OUT16(IoC, MR_ADDR(MAC_1, RX_MFF_CTRL1), MFF_CLR_INTIST);
+               }
+
+               if ((HwStatus & IS_NO_TIST_M2) != 0) {
+                       /* Ignore it */
+                       /* This situation is also indicated in the descriptor */
+                       SK_OUT16(IoC, MR_ADDR(MAC_2, RX_MFF_CTRL1), MFF_CLR_INTIST);
+               }
+       }
+#endif /* GENESIS */
+       
+#ifdef YUKON
+       if (pAC->GIni.GIYukon) {
+               /* This is necessary only for Rx timing measurements */
+               if ((HwStatus & IS_IRQ_TIST_OV) != 0) {
+                       /* increment Time Stamp Timer counter (high) */
+                       pAC->GIni.GITimeStampCnt++;
+
+                       /* Clear Time Stamp Timer IRQ */
+                       SK_OUT8(IoC, GMAC_TI_ST_CTRL, (SK_U8)GMT_ST_CLR_IRQ);
+               }
+
+               if ((HwStatus & IS_IRQ_SENSOR) != 0) {
+                       /* no sensors on 32-bit Yukon */
+                       if (pAC->GIni.GIYukon32Bit) {
+                               /* disable HW Error IRQ */
+                               pAC->GIni.GIValIrqMask &= ~IS_HW_ERR;
+                       }
+               }
+       }
+#endif /* YUKON */
+
+       if ((HwStatus & IS_RAM_RD_PAR) != 0) {
+               SK_OUT16(IoC, B3_RI_CTRL, RI_CLR_RD_PERR);
+               SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_SIRQ_E014, SKERR_SIRQ_E014MSG);
+               Para.Para64 = 0;
+               SkEventQueue(pAC, SKGE_DRV, SK_DRV_ADAP_FAIL, Para);
+       }
+
+       if ((HwStatus & IS_RAM_WR_PAR) != 0) {
+               SK_OUT16(IoC, B3_RI_CTRL, RI_CLR_WR_PERR);
+               SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_SIRQ_E015, SKERR_SIRQ_E015MSG);
+               Para.Para64 = 0;
+               SkEventQueue(pAC, SKGE_DRV, SK_DRV_ADAP_FAIL, Para);
+       }
+
+       if ((HwStatus & IS_M1_PAR_ERR) != 0) {
+               SkMacParity(pAC, IoC, MAC_1);
+       }
+
+       if ((HwStatus & IS_M2_PAR_ERR) != 0) {
+               SkMacParity(pAC, IoC, MAC_2);
+       }
+
+       if ((HwStatus & IS_R1_PAR_ERR) != 0) {
+               /* Clear IRQ */
+               SK_OUT32(IoC, B0_R1_CSR, CSR_IRQ_CL_P);
+
+               SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_SIRQ_E018, SKERR_SIRQ_E018MSG);
+               Para.Para64 = MAC_1;
+               SkEventQueue(pAC, SKGE_DRV, SK_DRV_PORT_FAIL, Para);
+               
+               Para.Para32[0] = MAC_1;
+               SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_LINK_DOWN, Para);
+       }
+
+       if ((HwStatus & IS_R2_PAR_ERR) != 0) {
+               /* Clear IRQ */
+               SK_OUT32(IoC, B0_R2_CSR, CSR_IRQ_CL_P);
+
+               SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_SIRQ_E019, SKERR_SIRQ_E019MSG);
+               Para.Para64 = MAC_2;
+               SkEventQueue(pAC, SKGE_DRV, SK_DRV_PORT_FAIL, Para);
+               
+               Para.Para32[0] = MAC_2;
+               SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_LINK_DOWN, Para);
+       }
+}      /* SkGeHwErr */
+
+
+/******************************************************************************
+ *
+ *     SkGeSirqIsr() - Special Interrupt Service Routine
+ *
+ * Description: handles all non data transfer specific interrupts (slow path)
+ *
+ * Returns: N/A
+ */
+void SkGeSirqIsr(
+SK_AC  *pAC,           /* adapter context */
+SK_IOC IoC,            /* IO context */
+SK_U32 Istatus)        /* Interrupt status word */
+{
+       SK_EVPARA       Para;
+       SK_U32          RegVal32;       /* Read register value */
+       SK_GEPORT       *pPrt;          /* GIni Port struct pointer */
+       SK_U16          PhyInt;
+       int                     i;
+
+       if (((Istatus & IS_HW_ERR) & pAC->GIni.GIValIrqMask) != 0) {
+               /* read the HW Error Interrupt source */
+               SK_IN32(IoC, B0_HWE_ISRC, &RegVal32);
+               
+               SkGeHwErr(pAC, IoC, RegVal32);
+       }
+
+       /*
+        * Packet Timeout interrupts
+        */
+       /* Check whether MACs are correctly initialized */
+       if (((Istatus & (IS_PA_TO_RX1 | IS_PA_TO_TX1)) != 0) &&
+               pAC->GIni.GP[MAC_1].PState == SK_PRT_RESET) {
+               /* MAC 1 was not initialized but Packet timeout occured */
+               SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_SIRQ_E004,
+                       SKERR_SIRQ_E004MSG);
+       }
+
+       if (((Istatus & (IS_PA_TO_RX2 | IS_PA_TO_TX2)) != 0) &&
+           pAC->GIni.GP[MAC_2].PState == SK_PRT_RESET) {
+               /* MAC 2 was not initialized but Packet timeout occured */
+               SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_SIRQ_E005,
+                       SKERR_SIRQ_E005MSG);
+       }
+
+       if ((Istatus & IS_PA_TO_RX1) != 0) {
+               /* Means network is filling us up */
+               SK_ERR_LOG(pAC, SK_ERRCL_HW | SK_ERRCL_INIT, SKERR_SIRQ_E002,
+                       SKERR_SIRQ_E002MSG);
+               SK_OUT16(IoC, B3_PA_CTRL, PA_CLR_TO_RX1);
+       }
+
+       if ((Istatus & IS_PA_TO_RX2) != 0) {
+               /* Means network is filling us up */
+               SK_ERR_LOG(pAC, SK_ERRCL_HW | SK_ERRCL_INIT, SKERR_SIRQ_E003,
+                       SKERR_SIRQ_E003MSG);
+               SK_OUT16(IoC, B3_PA_CTRL, PA_CLR_TO_RX2);
+       }
+
+       if ((Istatus & IS_PA_TO_TX1) != 0) {
+               
+               pPrt = &pAC->GIni.GP[0];
+
+               /* May be a normal situation in a server with a slow network */
+               SK_OUT16(IoC, B3_PA_CTRL, PA_CLR_TO_TX1);
+
+#ifdef GENESIS
+               if (pAC->GIni.GIGenesis) {
+                       /*
+                        * workaround: if in half duplex mode, check for Tx hangup.
+                        * Read number of TX'ed bytes, wait for 10 ms, then compare
+                        * the number with current value. If nothing changed, we assume
+                        * that Tx is hanging and do a FIFO flush (see event routine).
+                        */
+                       if ((pPrt->PLinkModeStatus == SK_LMODE_STAT_HALF ||
+                               pPrt->PLinkModeStatus == SK_LMODE_STAT_AUTOHALF) &&
+                               !pPrt->HalfDupTimerActive) {
+                               /*
+                                * many more pack. arb. timeouts may come in between,
+                                * we ignore those
+                                */
+                               pPrt->HalfDupTimerActive = SK_TRUE;
+                               /* Snap statistic counters */
+                               (void)SkXmUpdateStats(pAC, IoC, 0);
+
+                               (void)SkXmMacStatistic(pAC, IoC, 0, XM_TXO_OK_HI, &RegVal32);
+
+                               pPrt->LastOctets = (SK_U64)RegVal32 << 32;
+                               
+                               (void)SkXmMacStatistic(pAC, IoC, 0, XM_TXO_OK_LO, &RegVal32);
+
+                               pPrt->LastOctets += RegVal32;
+                               
+                               Para.Para32[0] = 0;
+                               SkTimerStart(pAC, IoC, &pPrt->HalfDupChkTimer, SK_HALFDUP_CHK_TIME,
+                                       SKGE_HWAC, SK_HWEV_HALFDUP_CHK, Para);
+                       }
+               }
+#endif /* GENESIS */
+       }
+
+       if ((Istatus & IS_PA_TO_TX2) != 0) {
+               
+               pPrt = &pAC->GIni.GP[1];
+
+               /* May be a normal situation in a server with a slow network */
+               SK_OUT16(IoC, B3_PA_CTRL, PA_CLR_TO_TX2);
+
+#ifdef GENESIS
+               if (pAC->GIni.GIGenesis) {
+                       /* workaround: see above */
+                       if ((pPrt->PLinkModeStatus == SK_LMODE_STAT_HALF ||
+                                pPrt->PLinkModeStatus == SK_LMODE_STAT_AUTOHALF) &&
+                               !pPrt->HalfDupTimerActive) {
+                               pPrt->HalfDupTimerActive = SK_TRUE;
+                               /* Snap statistic counters */
+                               (void)SkXmUpdateStats(pAC, IoC, 1);
+
+                               (void)SkXmMacStatistic(pAC, IoC, 1, XM_TXO_OK_HI, &RegVal32);
+
+                               pPrt->LastOctets = (SK_U64)RegVal32 << 32;
+                               
+                               (void)SkXmMacStatistic(pAC, IoC, 1, XM_TXO_OK_LO, &RegVal32);
+
+                               pPrt->LastOctets += RegVal32;
+                               
+                               Para.Para32[0] = 1;
+                               SkTimerStart(pAC, IoC, &pPrt->HalfDupChkTimer, SK_HALFDUP_CHK_TIME,
+                                       SKGE_HWAC, SK_HWEV_HALFDUP_CHK, Para);
+                       }
+               }
+#endif /* GENESIS */
+       }
+
+       /* Check interrupts of the particular queues */
+       if ((Istatus & IS_R1_C) != 0) {
+               /* Clear IRQ */
+               SK_OUT32(IoC, B0_R1_CSR, CSR_IRQ_CL_C);
+               SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_SIRQ_E006,
+                       SKERR_SIRQ_E006MSG);
+               Para.Para64 = MAC_1;
+               SkEventQueue(pAC, SKGE_DRV, SK_DRV_PORT_FAIL, Para);
+               Para.Para32[0] = MAC_1;
+               SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_LINK_DOWN, Para);
+       }
+
+       if ((Istatus & IS_R2_C) != 0) {
+               /* Clear IRQ */
+               SK_OUT32(IoC, B0_R2_CSR, CSR_IRQ_CL_C);
+               SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_SIRQ_E007,
+                       SKERR_SIRQ_E007MSG);
+               Para.Para64 = MAC_2;
+               SkEventQueue(pAC, SKGE_DRV, SK_DRV_PORT_FAIL, Para);
+               Para.Para32[0] = MAC_2;
+               SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_LINK_DOWN, Para);
+       }
+
+       if ((Istatus & IS_XS1_C) != 0) {
+               /* Clear IRQ */
+               SK_OUT32(IoC, B0_XS1_CSR, CSR_IRQ_CL_C);
+               SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_SIRQ_E008,
+                       SKERR_SIRQ_E008MSG);
+               Para.Para64 = MAC_1;
+               SkEventQueue(pAC, SKGE_DRV, SK_DRV_PORT_FAIL, Para);
+               Para.Para32[0] = MAC_1;
+               SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_LINK_DOWN, Para);
+       }
+
+       if ((Istatus & IS_XA1_C) != 0) {
+               /* Clear IRQ */
+               SK_OUT32(IoC, B0_XA1_CSR, CSR_IRQ_CL_C);
+               SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_SIRQ_E009,
+                       SKERR_SIRQ_E009MSG);
+               Para.Para64 = MAC_1;
+               SkEventQueue(pAC, SKGE_DRV, SK_DRV_PORT_FAIL, Para);
+               Para.Para32[0] = MAC_1;
+               SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_LINK_DOWN, Para);
+       }
+
+       if ((Istatus & IS_XS2_C) != 0) {
+               /* Clear IRQ */
+               SK_OUT32(IoC, B0_XS2_CSR, CSR_IRQ_CL_C);
+               SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_SIRQ_E010,
+                       SKERR_SIRQ_E010MSG);
+               Para.Para64 = MAC_2;
+               SkEventQueue(pAC, SKGE_DRV, SK_DRV_PORT_FAIL, Para);
+               Para.Para32[0] = MAC_2;
+               SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_LINK_DOWN, Para);
+       }
+
+       if ((Istatus & IS_XA2_C) != 0) {
+               /* Clear IRQ */
+               SK_OUT32(IoC, B0_XA2_CSR, CSR_IRQ_CL_C);
+               SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_SIRQ_E011,
+                       SKERR_SIRQ_E011MSG);
+               Para.Para64 = MAC_2;
+               SkEventQueue(pAC, SKGE_DRV, SK_DRV_PORT_FAIL, Para);
+               Para.Para32[0] = MAC_2;
+               SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_LINK_DOWN, Para);
+       }
+
+       /* External reg interrupt */
+       if ((Istatus & IS_EXT_REG) != 0) {
+               /* Test IRQs from PHY */
+               for (i = 0; i < pAC->GIni.GIMacsFound; i++) {
+                       
+                       pPrt = &pAC->GIni.GP[i];
+                       
+                       if (pPrt->PState == SK_PRT_RESET) {
+                               continue;
+                       }
+                       
+#ifdef GENESIS
+                       if (pAC->GIni.GIGenesis) {
+                               
+                               switch (pPrt->PhyType) {
+                               
+                               case SK_PHY_XMAC:
+                                       break;
+                               
+                               case SK_PHY_BCOM:
+                                       SkXmPhyRead(pAC, IoC, i, PHY_BCOM_INT_STAT, &PhyInt);
+       
+                                       if ((PhyInt & ~PHY_B_DEF_MSK) != 0) {
+                                               SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ,
+                                                       ("Port %d Bcom Int: 0x%04X\n",
+                                                       i, PhyInt));
+                                               SkPhyIsrBcom(pAC, IoC, i, PhyInt);
+                                       }
+                                       break;
+#ifdef OTHER_PHY
+                               case SK_PHY_LONE:
+                                       SkXmPhyRead(pAC, IoC, i, PHY_LONE_INT_STAT, &PhyInt);
+                                       
+                                       if ((PhyInt & PHY_L_DEF_MSK) != 0) {
+                                               SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ,
+                                                       ("Port %d Lone Int: %x\n",
+                                                       i, PhyInt));
+                                               SkPhyIsrLone(pAC, IoC, i, PhyInt);
+                                       }
+                                       break;
+#endif /* OTHER_PHY */
+                               }
+                       }
+#endif /* GENESIS */
+       
+#ifdef YUKON
+                       if (pAC->GIni.GIYukon) {
+                               /* Read PHY Interrupt Status */
+                               SkGmPhyRead(pAC, IoC, i, PHY_MARV_INT_STAT, &PhyInt);
+
+                               if ((PhyInt & PHY_M_DEF_MSK) != 0) {
+                                       SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ,
+                                               ("Port %d Marv Int: 0x%04X\n",
+                                               i, PhyInt));
+                                       SkPhyIsrGmac(pAC, IoC, i, PhyInt);
+                               }
+                       }
+#endif /* YUKON */
+               }
+       }
+
+       /* I2C Ready interrupt */
+       if ((Istatus & IS_I2C_READY) != 0) {
+#ifdef SK_SLIM
+        SK_OUT32(IoC, B2_I2C_IRQ, I2C_CLR_IRQ);
+#else          
+               SkI2cIsr(pAC, IoC);
+#endif         
+       }
+
+       /* SW forced interrupt */
+       if ((Istatus & IS_IRQ_SW) != 0) {
+               /* clear the software IRQ */
+               SK_OUT8(IoC, B0_CTST, CS_CL_SW_IRQ);
+       }
+
+       if ((Istatus & IS_LNK_SYNC_M1) != 0) {
+               /*
+                * We do NOT need the Link Sync interrupt, because it shows
+                * us only a link going down.
+                */
+               /* clear interrupt */
+               SK_OUT8(IoC, MR_ADDR(MAC_1, LNK_SYNC_CTRL), LED_CLR_IRQ);
+       }
+
+       /* Check MAC after link sync counter */
+       if ((Istatus & IS_MAC1) != 0) {
+               /* IRQ from MAC 1 */
+               SkMacIrq(pAC, IoC, MAC_1);
+       }
+
+       if ((Istatus & IS_LNK_SYNC_M2) != 0) {
+               /*
+                * We do NOT need the Link Sync interrupt, because it shows
+                * us only a link going down.
+                */
+               /* clear interrupt */
+               SK_OUT8(IoC, MR_ADDR(MAC_2, LNK_SYNC_CTRL), LED_CLR_IRQ);
+       }
+
+       /* Check MAC after link sync counter */
+       if ((Istatus & IS_MAC2) != 0) {
+               /* IRQ from MAC 2 */
+               SkMacIrq(pAC, IoC, MAC_2);
+       }
+
+       /* Timer interrupt (served last) */
+       if ((Istatus & IS_TIMINT) != 0) {
+               /* check for HW Errors */
+               if (((Istatus & IS_HW_ERR) & ~pAC->GIni.GIValIrqMask) != 0) {
+                       /* read the HW Error Interrupt source */
+                       SK_IN32(IoC, B0_HWE_ISRC, &RegVal32);
+
+                       SkGeHwErr(pAC, IoC, RegVal32);
+               }
+
+               SkHwtIsr(pAC, IoC);
+       }
+
+}      /* SkGeSirqIsr */
+
+
+#ifdef GENESIS
+/******************************************************************************
+ *
+ * SkGePortCheckShorts() - Implementing XMAC Workaround Errata # 2
+ *
+ * return:
+ *     0       o.k. nothing needed
+ *     1       Restart needed on this port
+ */
+static int SkGePortCheckShorts(
+SK_AC  *pAC,           /* Adapter Context */
+SK_IOC IoC,            /* IO Context */
+int            Port)           /* Which port should be checked */
+{
+       SK_U32          Shorts;                 /* Short Event Counter */
+       SK_U32          CheckShorts;    /* Check value for Short Event Counter */
+       SK_U64          RxCts;                  /* Rx Counter (packets on network) */
+       SK_U32          RxTmp;                  /* Rx temp. Counter */
+       SK_U32          FcsErrCts;              /* FCS Error Counter */
+       SK_GEPORT       *pPrt;                  /* GIni Port struct pointer */
+       int                     Rtv;                    /* Return value */
+       int                     i;
+
+       pPrt = &pAC->GIni.GP[Port];
+
+       /* Default: no action */
+       Rtv = SK_HW_PS_NONE;
+
+       (void)SkXmUpdateStats(pAC, IoC, Port);
+
+       /* Extra precaution: check for short Event counter */
+       (void)SkXmMacStatistic(pAC, IoC, Port, XM_RXE_SHT_ERR, &Shorts);
+
+       /*
+        * Read Rx counters (packets seen on the network and not necessarily
+        * really received.
+        */
+       RxCts = 0;
+
+       for (i = 0; i < sizeof(SkGeRxRegs)/sizeof(SkGeRxRegs[0]); i++) {
+               
+               (void)SkXmMacStatistic(pAC, IoC, Port, SkGeRxRegs[i], &RxTmp);
+               
+               RxCts += (SK_U64)RxTmp;
+       }
+
+       /* On default: check shorts against zero */
+       CheckShorts = 0;
+
+       /* Extra precaution on active links */
+       if (pPrt->PHWLinkUp) {
+               /* Reset Link Restart counter */
+               pPrt->PLinkResCt = 0;
+               pPrt->PAutoNegTOCt = 0;
+
+               /* If link is up check for 2 */
+               CheckShorts = 2;
+
+               (void)SkXmMacStatistic(pAC, IoC, Port, XM_RXF_FCS_ERR, &FcsErrCts);
+               
+               if (pPrt->PLinkModeConf == SK_LMODE_AUTOSENSE &&
+                   pPrt->PLipaAutoNeg == SK_LIPA_UNKNOWN &&
+                   (pPrt->PLinkMode == SK_LMODE_HALF ||
+                        pPrt->PLinkMode == SK_LMODE_FULL)) {
+                       /*
+                        * This is autosensing and we are in the fallback
+                        * manual full/half duplex mode.
+                        */
+                       if (RxCts == pPrt->PPrevRx) {
+                               /* Nothing received, restart link */
+                               pPrt->PPrevFcs = FcsErrCts;
+                               pPrt->PPrevShorts = Shorts;
+                               
+                               return(SK_HW_PS_RESTART);
+                       }
+                       else {
+                               pPrt->PLipaAutoNeg = SK_LIPA_MANUAL;
+                       }
+               }
+
+               if (((RxCts - pPrt->PPrevRx) > pPrt->PRxLim) ||
+                   (!(FcsErrCts - pPrt->PPrevFcs))) {
+                       /*
+                        * Note: The compare with zero above has to be done the way shown,
+                        * otherwise the Linux driver will have a problem.
+                        */
+                       /*
+                        * We received a bunch of frames or no CRC error occured on the
+                        * network -> ok.
+                        */
+                       pPrt->PPrevRx = RxCts;
+                       pPrt->PPrevFcs = FcsErrCts;
+                       pPrt->PPrevShorts = Shorts;
+
+                       return(SK_HW_PS_NONE);
+               }
+
+               pPrt->PPrevFcs = FcsErrCts;
+       }
+
+
+       if ((Shorts - pPrt->PPrevShorts) > CheckShorts) {
+               SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ,
+                       ("Short Event Count Restart Port %d \n", Port));
+               Rtv = SK_HW_PS_RESTART;
+       }
+
+       pPrt->PPrevShorts = Shorts;
+       pPrt->PPrevRx = RxCts;
+
+       return(Rtv);
+}      /* SkGePortCheckShorts */
+#endif /* GENESIS */
+
+
+/******************************************************************************
+ *
+ * SkGePortCheckUp() - Check if the link is up
+ *
+ * return:
+ *     0       o.k. nothing needed
+ *     1       Restart needed on this port
+ *     2       Link came up
+ */
+static int SkGePortCheckUp(
+SK_AC  *pAC,           /* Adapter Context */
+SK_IOC IoC,            /* IO Context */
+int            Port)           /* Which port should be checked */
+{
+       SK_GEPORT       *pPrt;          /* GIni Port struct pointer */
+       SK_BOOL         AutoNeg;        /* Is Auto-negotiation used ? */
+       int                     Rtv;            /* Return value */
+
+       Rtv = SK_HW_PS_NONE;
+       
+       pPrt = &pAC->GIni.GP[Port];
+
+       if (pPrt->PLinkMode == SK_LMODE_HALF || pPrt->PLinkMode == SK_LMODE_FULL) {
+               AutoNeg = SK_FALSE;
+       }
+       else {
+               AutoNeg = SK_TRUE;
+       }
+
+#ifdef GENESIS
+       if (pAC->GIni.GIGenesis) {
+
+               switch (pPrt->PhyType) {
+               
+               case SK_PHY_XMAC:
+                       Rtv = SkGePortCheckUpXmac(pAC, IoC, Port, AutoNeg);
+                       break;
+               case SK_PHY_BCOM:
+                       Rtv = SkGePortCheckUpBcom(pAC, IoC, Port, AutoNeg);
+                       break;
+#ifdef OTHER_PHY
+               case SK_PHY_LONE:
+                       Rtv = SkGePortCheckUpLone(pAC, IoC, Port, AutoNeg);
+                       break;
+               case SK_PHY_NAT:
+                       Rtv = SkGePortCheckUpNat(pAC, IoC, Port, AutoNeg);
+                       break;
+#endif /* OTHER_PHY */
+               }
+       }
+#endif /* GENESIS */
+       
+#ifdef YUKON
+       if (pAC->GIni.GIYukon) {
+               
+               Rtv = SkGePortCheckUpGmac(pAC, IoC, Port, AutoNeg);
+       }
+#endif /* YUKON */
+
+       return(Rtv);    
+}      /* SkGePortCheckUp */
+
+
+#ifdef GENESIS
+/******************************************************************************
+ *
+ * SkGePortCheckUpXmac() - Implementing of the Workaround Errata # 2
+ *
+ * return:
+ *     0       o.k. nothing needed
+ *     1       Restart needed on this port
+ *     2       Link came up
+ */
+static int SkGePortCheckUpXmac(
+SK_AC  *pAC,           /* Adapter Context */
+SK_IOC IoC,            /* IO Context */
+int            Port,           /* Which port should be checked */
+SK_BOOL        AutoNeg)        /* Is Auto-negotiation used ? */
+{
+       SK_U32          Shorts;         /* Short Event Counter */
+       SK_GEPORT       *pPrt;          /* GIni Port struct pointer */
+       int                     Done;
+       SK_U32          GpReg;          /* General Purpose register value */
+       SK_U16          Isrc;           /* Interrupt source register */
+       SK_U16          IsrcSum;        /* Interrupt source register sum */
+       SK_U16          LpAb;           /* Link Partner Ability */
+       SK_U16          ResAb;          /* Resolved Ability */
+       SK_U16          ExtStat;        /* Extended Status Register */
+       SK_U8           NextMode;       /* Next AutoSensing Mode */
+
+       pPrt = &pAC->GIni.GP[Port];
+
+       if (pPrt->PHWLinkUp) {
+               if (pPrt->PhyType != SK_PHY_XMAC) {
+                       return(SK_HW_PS_NONE);
+               }
+               else {
+                       return(SkGePortCheckShorts(pAC, IoC, Port));
+               }
+       }
+
+       IsrcSum = pPrt->PIsave;
+       pPrt->PIsave = 0;
+
+       /* Now wait for each port's link */
+       if (pPrt->PLinkBroken) {
+               /* Link was broken */
+               XM_IN32(IoC, Port, XM_GP_PORT, &GpReg);
+
+               if ((GpReg & XM_GP_INP_ASS) == 0) {
+                       /* The Link is in sync */
+                       XM_IN16(IoC, Port, XM_ISRC, &Isrc);
+                       IsrcSum |= Isrc;
+                       SkXmAutoNegLipaXmac(pAC, IoC, Port, IsrcSum);
+                       
+                       if ((Isrc & XM_IS_INP_ASS) == 0) {
+                               /* It has been in sync since last time */
+                               /* Restart the PORT */
+                               SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ,
+                                       ("Link in sync Restart Port %d\n", Port));
+
+                               (void)SkXmUpdateStats(pAC, IoC, Port);
+
+                               /* We now need to reinitialize the PrevShorts counter */
+                               (void)SkXmMacStatistic(pAC, IoC, Port, XM_RXE_SHT_ERR, &Shorts);
+                               pPrt->PPrevShorts = Shorts;
+
+                               pPrt->PLinkBroken = SK_FALSE;
+
+                               /*
+                                * Link Restart Workaround:
+                                *  it may be possible that the other Link side
+                                *  restarts its link as well an we detect
+                                *  another LinkBroken. To prevent this
+                                *  happening we check for a maximum number
+                                *  of consecutive restart. If those happens,
+                                *  we do NOT restart the active link and
+                                *  check whether the link is now o.k.
+                                */
+                               pPrt->PLinkResCt++;
+                               
+                               pPrt->PAutoNegTimeOut = 0;
+
+                               if (pPrt->PLinkResCt < SK_MAX_LRESTART) {
+                                       return(SK_HW_PS_RESTART);
+                               }
+
+                               pPrt->PLinkResCt = 0;
+                               
+                               SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+                                       ("Do NOT restart on Port %d %x %x\n", Port, Isrc, IsrcSum));
+                       }
+                       else {
+                               pPrt->PIsave = (SK_U16)(IsrcSum & XM_IS_AND);
+                               
+                               SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+                                       ("Save Sync/nosync Port %d %x %x\n", Port, Isrc, IsrcSum));
+
+                               /* Do nothing more if link is broken */
+                               return(SK_HW_PS_NONE);
+                       }
+               }
+               else {
+                       /* Do nothing more if link is broken */
+                       return(SK_HW_PS_NONE);
+               }
+
+       }
+       else {
+               /* Link was not broken, check if it is */
+               XM_IN16(IoC, Port, XM_ISRC, &Isrc);
+               IsrcSum |= Isrc;
+               if ((Isrc & XM_IS_INP_ASS) != 0) {
+                       XM_IN16(IoC, Port, XM_ISRC, &Isrc);
+                       IsrcSum |= Isrc;
+                       if ((Isrc & XM_IS_INP_ASS) != 0) {
+                               XM_IN16(IoC, Port, XM_ISRC, &Isrc);
+                               IsrcSum |= Isrc;
+                               if ((Isrc & XM_IS_INP_ASS) != 0) {
+                                       pPrt->PLinkBroken = SK_TRUE;
+                                       /* Re-Init Link partner Autoneg flag */
+                                       pPrt->PLipaAutoNeg = SK_LIPA_UNKNOWN;
+                                       SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ,
+                                               ("Link broken Port %d\n", Port));
+
+                                       /* Cable removed-> reinit sense mode */
+                                       SkHWInitDefSense(pAC, IoC, Port);
+
+                                       return(SK_HW_PS_RESTART);
+                               }
+                       }
+               }
+               else {
+                       SkXmAutoNegLipaXmac(pAC, IoC, Port, Isrc);
+                       
+                       if (SkGePortCheckShorts(pAC, IoC, Port) == SK_HW_PS_RESTART) {
+                               return(SK_HW_PS_RESTART);
+                       }
+               }
+       }
+
+       /*
+        * here we usually can check whether the link is in sync and
+        * auto-negotiation is done.
+        */
+       XM_IN32(IoC, Port, XM_GP_PORT, &GpReg);
+       XM_IN16(IoC, Port, XM_ISRC, &Isrc);
+       IsrcSum |= Isrc;
+
+       SkXmAutoNegLipaXmac(pAC, IoC, Port, IsrcSum);
+       
+       if ((GpReg & XM_GP_INP_ASS) != 0 || (IsrcSum & XM_IS_INP_ASS) != 0) {
+               if ((GpReg & XM_GP_INP_ASS) == 0) {
+                       /* Save Auto-negotiation Done interrupt only if link is in sync */
+                       pPrt->PIsave = (SK_U16)(IsrcSum & XM_IS_AND);
+               }
+#ifdef DEBUG
+               if ((pPrt->PIsave & XM_IS_AND) != 0) {
+                       SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+                               ("AutoNeg done rescheduled Port %d\n", Port));
+               }
+#endif /* DEBUG */
+               return(SK_HW_PS_NONE);
+       }
+
+       if (AutoNeg) {
+               if ((IsrcSum & XM_IS_AND) != 0) {
+                       SkHWLinkUp(pAC, IoC, Port);
+                       Done = SkMacAutoNegDone(pAC, IoC, Port);
+                       if (Done != SK_AND_OK) {
+                               /* Get PHY parameters, for debugging only */
+                               SkXmPhyRead(pAC, IoC, Port, PHY_XMAC_AUNE_LP, &LpAb);
+                               SkXmPhyRead(pAC, IoC, Port, PHY_XMAC_RES_ABI, &ResAb);
+                               SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+                                       ("AutoNeg FAIL Port %d (LpAb %x, ResAb %x)\n",
+                                        Port, LpAb, ResAb));
+                                       
+                               /* Try next possible mode */
+                               NextMode = SkHWSenseGetNext(pAC, IoC, Port);
+                               SkHWLinkDown(pAC, IoC, Port);
+                               if (Done == SK_AND_DUP_CAP) {
+                                       /* GoTo next mode */
+                                       SkHWSenseSetNext(pAC, IoC, Port, NextMode);
+                               }
+
+                               return(SK_HW_PS_RESTART);
+                       }
+                       /*
+                        * Dummy Read extended status to prevent extra link down/ups
+                        * (clear Page Received bit if set)
+                        */
+                       SkXmPhyRead(pAC, IoC, Port, PHY_XMAC_AUNE_EXP, &ExtStat);
+                       
+                       return(SK_HW_PS_LINK);
+               }
+               
+               /* AutoNeg not done, but HW link is up. Check for timeouts */
+               pPrt->PAutoNegTimeOut++;
+               if (pPrt->PAutoNegTimeOut >= SK_AND_MAX_TO) {
+                       /* Increase the Timeout counter */
+                       pPrt->PAutoNegTOCt++;
+
+                       /* Timeout occured */
+                       SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ,
+                               ("AutoNeg timeout Port %d\n", Port));
+                       if (pPrt->PLinkModeConf == SK_LMODE_AUTOSENSE &&
+                               pPrt->PLipaAutoNeg != SK_LIPA_AUTO) {
+                               /* Set Link manually up */
+                               SkHWSenseSetNext(pAC, IoC, Port, SK_LMODE_FULL);
+                               SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ,
+                                       ("Set manual full duplex Port %d\n", Port));
+                       }
+
+                       if (pPrt->PLinkModeConf == SK_LMODE_AUTOSENSE &&
+                               pPrt->PLipaAutoNeg == SK_LIPA_AUTO &&
+                               pPrt->PAutoNegTOCt >= SK_MAX_ANEG_TO) {
+                               /*
+                                * This is rather complicated.
+                                * we need to check here whether the LIPA_AUTO
+                                * we saw before is false alert. We saw at one
+                                * switch ( SR8800) that on boot time it sends
+                                * just one auto-neg packet and does no further
+                                * auto-negotiation.
+                                * Solution: we restart the autosensing after
+                                * a few timeouts.
+                                */
+                               pPrt->PAutoNegTOCt = 0;
+                               pPrt->PLipaAutoNeg = SK_LIPA_UNKNOWN;
+                               SkHWInitDefSense(pAC, IoC, Port);
+                       }
+
+                       /* Do the restart */
+                       return(SK_HW_PS_RESTART);
+               }
+       }
+       else {
+               /* Link is up and we don't need more */
+#ifdef DEBUG
+               if (pPrt->PLipaAutoNeg == SK_LIPA_AUTO) {
+                       SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+                               ("ERROR: Lipa auto detected on port %d\n", Port));
+               }
+#endif /* DEBUG */
+               SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ,
+                       ("Link sync(GP), Port %d\n", Port));
+               SkHWLinkUp(pAC, IoC, Port);
+               
+               /*
+                * Link sync (GP) and so assume a good connection. But if not received
+                * a bunch of frames received in a time slot (maybe broken tx cable)
+                * the port is restart.
+                */
+               return(SK_HW_PS_LINK);
+       }
+
+       return(SK_HW_PS_NONE);
+}      /* SkGePortCheckUpXmac */
+
+
+/******************************************************************************
+ *
+ * SkGePortCheckUpBcom() - Check if the link is up on Bcom PHY
+ *
+ * return:
+ *     0       o.k. nothing needed
+ *     1       Restart needed on this port
+ *     2       Link came up
+ */
+static int SkGePortCheckUpBcom(
+SK_AC  *pAC,           /* Adapter Context */
+SK_IOC IoC,            /* IO Context */
+int            Port,           /* Which port should be checked */
+SK_BOOL        AutoNeg)        /* Is Auto-negotiation used ? */
+{
+       SK_GEPORT       *pPrt;          /* GIni Port struct pointer */
+       int                     Done;
+       SK_U16          Isrc;           /* Interrupt source register */
+       SK_U16          PhyStat;        /* Phy Status Register */
+       SK_U16          ResAb;          /* Master/Slave resolution */
+       SK_U16          Ctrl;           /* Broadcom control flags */
+#ifdef DEBUG
+       SK_U16          LpAb;
+       SK_U16          ExtStat;
+#endif /* DEBUG */
+
+       pPrt = &pAC->GIni.GP[Port];
+
+       /* Check for No HCD Link events (#10523) */
+       SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_INT_STAT, &Isrc);
+
+#ifdef xDEBUG
+       if ((Isrc & ~(PHY_B_IS_HCT | PHY_B_IS_LCT)) ==
+               (PHY_B_IS_SCR_S_ER | PHY_B_IS_RRS_CHANGE | PHY_B_IS_LRS_CHANGE)) {
+
+               SK_U32  Stat1, Stat2, Stat3;
+
+               Stat1 = 0;
+               SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_INT_MASK, &Stat1);
+               CMSMPrintString(
+                       pAC->pConfigTable,
+                       MSG_TYPE_RUNTIME_INFO,
+                       "CheckUp1 - Stat: %x, Mask: %x",
+                       (void *)Isrc,
+                       (void *)Stat1);
+
+               Stat1 = 0;
+               SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_CTRL, &Stat1);
+               Stat2 = 0;
+               SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_STAT, &Stat2);
+               Stat1 = Stat1 << 16 | Stat2;
+               Stat2 = 0;
+               SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_AUNE_ADV, &Stat2);
+               Stat3 = 0;
+               SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_AUNE_LP, &Stat3);
+               Stat2 = Stat2 << 16 | Stat3;
+               CMSMPrintString(
+                       pAC->pConfigTable,
+                       MSG_TYPE_RUNTIME_INFO,
+                       "Ctrl/Stat: %x, AN Adv/LP: %x",
+                       (void *)Stat1,
+                       (void *)Stat2);
+
+               Stat1 = 0;
+               SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_AUNE_EXP, &Stat1);
+               Stat2 = 0;
+               SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_EXT_STAT, &Stat2);
+               Stat1 = Stat1 << 16 | Stat2;
+               Stat2 = 0;
+               SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_1000T_CTRL, &Stat2);
+               Stat3 = 0;
+               SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_1000T_STAT, &Stat3);
+               Stat2 = Stat2 << 16 | Stat3;
+               CMSMPrintString(
+                       pAC->pConfigTable,
+                       MSG_TYPE_RUNTIME_INFO,
+                       "AN Exp/IEEE Ext: %x, 1000T Ctrl/Stat: %x",
+                       (void *)Stat1,
+                       (void *)Stat2);
+
+               Stat1 = 0;
+               SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_P_EXT_CTRL, &Stat1);
+               Stat2 = 0;
+               SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_P_EXT_STAT, &Stat2);
+               Stat1 = Stat1 << 16 | Stat2;
+               Stat2 = 0;
+               SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_AUX_CTRL, &Stat2);
+               Stat3 = 0;
+               SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_AUX_STAT, &Stat3);
+               Stat2 = Stat2 << 16 | Stat3;
+               CMSMPrintString(
+                       pAC->pConfigTable,
+                       MSG_TYPE_RUNTIME_INFO,
+                       "PHY Ext Ctrl/Stat: %x, Aux Ctrl/Stat: %x",
+                       (void *)Stat1,
+                       (void *)Stat2);
+       }
+#endif /* DEBUG */
+
+       if ((Isrc & (PHY_B_IS_NO_HDCL /* | PHY_B_IS_NO_HDC */)) != 0) {
+               /*
+                * Workaround BCom Errata:
+                *      enable and disable loopback mode if "NO HCD" occurs.
+                */
+               SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_CTRL, &Ctrl);
+               SkXmPhyWrite(pAC, IoC, Port, PHY_BCOM_CTRL,
+                       (SK_U16)(Ctrl | PHY_CT_LOOP));
+               SkXmPhyWrite(pAC, IoC, Port, PHY_BCOM_CTRL,
+                       (SK_U16)(Ctrl & ~PHY_CT_LOOP));
+               SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+                       ("No HCD Link event, Port %d\n", Port));
+#ifdef xDEBUG
+               CMSMPrintString(
+                       pAC->pConfigTable,
+                       MSG_TYPE_RUNTIME_INFO,
+                       "No HCD link event, port %d.",
+                       (void *)Port,
+                       (void *)NULL);
+#endif /* DEBUG */
+       }
+
+       /* Not obsolete: link status bit is latched to 0 and autoclearing! */
+       SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_STAT, &PhyStat);
+
+       if (pPrt->PHWLinkUp) {
+               return(SK_HW_PS_NONE);
+       }
+
+#ifdef xDEBUG
+       {
+               SK_U32  Stat1, Stat2, Stat3;
+
+               Stat1 = 0;
+               SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_INT_MASK, &Stat1);
+               CMSMPrintString(
+                       pAC->pConfigTable,
+                       MSG_TYPE_RUNTIME_INFO,
+                       "CheckUp1a - Stat: %x, Mask: %x",
+                       (void *)Isrc,
+                       (void *)Stat1);
+
+               Stat1 = 0;
+               SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_CTRL, &Stat1);
+               Stat2 = 0;
+               SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_STAT, &PhyStat);
+               Stat1 = Stat1 << 16 | PhyStat;
+               Stat2 = 0;
+               SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_AUNE_ADV, &Stat2);
+               Stat3 = 0;
+               SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_AUNE_LP, &Stat3);
+               Stat2 = Stat2 << 16 | Stat3;
+               CMSMPrintString(
+                       pAC->pConfigTable,
+                       MSG_TYPE_RUNTIME_INFO,
+                       "Ctrl/Stat: %x, AN Adv/LP: %x",
+                       (void *)Stat1,
+                       (void *)Stat2);
+
+               Stat1 = 0;
+               SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_AUNE_EXP, &Stat1);
+               Stat2 = 0;
+               SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_EXT_STAT, &Stat2);
+               Stat1 = Stat1 << 16 | Stat2;
+               Stat2 = 0;
+               SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_1000T_CTRL, &Stat2);
+               Stat3 = 0;
+               SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_1000T_STAT, &ResAb);
+               Stat2 = Stat2 << 16 | ResAb;
+               CMSMPrintString(
+                       pAC->pConfigTable,
+                       MSG_TYPE_RUNTIME_INFO,
+                       "AN Exp/IEEE Ext: %x, 1000T Ctrl/Stat: %x",
+                       (void *)Stat1,
+                       (void *)Stat2);
+
+               Stat1 = 0;
+               SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_P_EXT_CTRL, &Stat1);
+               Stat2 = 0;
+               SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_P_EXT_STAT, &Stat2);
+               Stat1 = Stat1 << 16 | Stat2;
+               Stat2 = 0;
+               SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_AUX_CTRL, &Stat2);
+               Stat3 = 0;
+               SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_AUX_STAT, &Stat3);
+               Stat2 = Stat2 << 16 | Stat3;
+               CMSMPrintString(
+                       pAC->pConfigTable,
+                       MSG_TYPE_RUNTIME_INFO,
+                       "PHY Ext Ctrl/Stat: %x, Aux Ctrl/Stat: %x",
+                       (void *)Stat1,
+                       (void *)Stat2);
+       }
+#endif /* DEBUG */
+
+       /*
+        * Here we usually can check whether the link is in sync and
+        * auto-negotiation is done.
+        */
+
+       SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_STAT, &PhyStat);
+
+       SkMacAutoNegLipaPhy(pAC, IoC, Port, PhyStat);
+       
+       SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+               ("CheckUp Port %d, PhyStat: 0x%04X\n", Port, PhyStat));
+
+       SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_1000T_STAT, &ResAb);
+
+       if ((ResAb & PHY_B_1000S_MSF) != 0) {
+               /* Error */
+               SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+                       ("Master/Slave Fault port %d\n", Port));
+               
+               pPrt->PAutoNegFail = SK_TRUE;
+               pPrt->PMSStatus = SK_MS_STAT_FAULT;
+               
+               return(SK_HW_PS_RESTART);
+       }
+
+       if ((PhyStat & PHY_ST_LSYNC) == 0) {
+               return(SK_HW_PS_NONE);
+       }
+       
+       pPrt->PMSStatus = ((ResAb & PHY_B_1000S_MSR) != 0) ?
+               SK_MS_STAT_MASTER : SK_MS_STAT_SLAVE;
+       
+       SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+               ("Port %d, ResAb: 0x%04X\n", Port, ResAb));
+
+       if (AutoNeg) {
+               if ((PhyStat & PHY_ST_AN_OVER) != 0) {
+                       
+                       SkHWLinkUp(pAC, IoC, Port);
+                       
+                       Done = SkMacAutoNegDone(pAC, IoC, Port);
+                       
+                       if (Done != SK_AND_OK) {
+#ifdef DEBUG
+                               /* Get PHY parameters, for debugging only */
+                               SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_AUNE_LP, &LpAb);
+                               SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_1000T_STAT, &ExtStat);
+                               SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+                                       ("AutoNeg FAIL Port %d (LpAb %x, 1000TStat %x)\n",
+                                       Port, LpAb, ExtStat));
+#endif /* DEBUG */
+                               return(SK_HW_PS_RESTART);
+                       }
+                       else {
+#ifdef xDEBUG
+                               /* Dummy read ISR to prevent extra link downs/ups */
+                               SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_INT_STAT, &ExtStat);
+
+                               if ((ExtStat & ~(PHY_B_IS_HCT | PHY_B_IS_LCT)) != 0) {
+                                       CMSMPrintString(
+                                               pAC->pConfigTable,
+                                               MSG_TYPE_RUNTIME_INFO,
+                                               "CheckUp2 - Stat: %x",
+                                               (void *)ExtStat,
+                                               (void *)NULL);
+                               }
+#endif /* DEBUG */
+                               return(SK_HW_PS_LINK);
+                       }
+               }
+       }
+       else {  /* !AutoNeg */
+               /* Link is up and we don't need more. */
+#ifdef DEBUG
+               if (pPrt->PLipaAutoNeg == SK_LIPA_AUTO) {
+                       SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+                               ("ERROR: Lipa auto detected on port %d\n", Port));
+               }
+#endif /* DEBUG */
+
+#ifdef xDEBUG
+               /* Dummy read ISR to prevent extra link downs/ups */
+               SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_INT_STAT, &ExtStat);
+
+               if ((ExtStat & ~(PHY_B_IS_HCT | PHY_B_IS_LCT)) != 0) {
+                       CMSMPrintString(
+                               pAC->pConfigTable,
+                               MSG_TYPE_RUNTIME_INFO,
+                               "CheckUp3 - Stat: %x",
+                               (void *)ExtStat,
+                               (void *)NULL);
+               }
+#endif /* DEBUG */
+               
+               SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ,
+                       ("Link sync(GP), Port %d\n", Port));
+               SkHWLinkUp(pAC, IoC, Port);
+               
+               return(SK_HW_PS_LINK);
+       }
+
+       return(SK_HW_PS_NONE);
+}      /* SkGePortCheckUpBcom */
+#endif /* GENESIS */
+
+
+#ifdef YUKON
+/******************************************************************************
+ *
+ * SkGePortCheckUpGmac() - Check if the link is up on Marvell PHY
+ *
+ * return:
+ *     0       o.k. nothing needed
+ *     1       Restart needed on this port
+ *     2       Link came up
+ */
+static int SkGePortCheckUpGmac(
+SK_AC  *pAC,           /* Adapter Context */
+SK_IOC IoC,            /* IO Context */
+int            Port,           /* Which port should be checked */
+SK_BOOL        AutoNeg)        /* Is Auto-negotiation used ? */
+{
+       SK_GEPORT       *pPrt;          /* GIni Port struct pointer */
+       int                     Done;
+       SK_U16          PhyIsrc;        /* PHY Interrupt source */
+       SK_U16          PhyStat;        /* PPY Status */
+       SK_U16          PhySpecStat;/* PHY Specific Status */
+       SK_U16          ResAb;          /* Master/Slave resolution */
+       SK_EVPARA       Para;
+#ifdef DEBUG
+       SK_U16          Word;           /* I/O helper */
+#endif /* DEBUG */
+
+       pPrt = &pAC->GIni.GP[Port];
+
+       if (pPrt->PHWLinkUp) {
+               return(SK_HW_PS_NONE);
+       }
+
+       /* Read PHY Status */
+       SkGmPhyRead(pAC, IoC, Port, PHY_MARV_STAT, &PhyStat);
+
+       SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+               ("CheckUp Port %d, PhyStat: 0x%04X\n", Port, PhyStat));
+
+       /* Read PHY Interrupt Status */
+       SkGmPhyRead(pAC, IoC, Port, PHY_MARV_INT_STAT, &PhyIsrc);
+
+       if ((PhyIsrc & PHY_M_IS_AN_COMPL) != 0) {
+               SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+                       ("Auto-Negotiation Completed, PhyIsrc: 0x%04X\n", PhyIsrc));
+       }
+
+       if ((PhyIsrc & PHY_M_IS_LSP_CHANGE) != 0) {
+               SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+                       ("Link Speed Changed, PhyIsrc: 0x%04X\n", PhyIsrc));
+       }
+
+       SkMacAutoNegLipaPhy(pAC, IoC, Port, PhyStat);
+       
+       SkGmPhyRead(pAC, IoC, Port, PHY_MARV_1000T_STAT, &ResAb);
+
+       if ((ResAb & PHY_B_1000S_MSF) != 0) {
+               /* Error */
+               SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+                       ("Master/Slave Fault port %d\n", Port));
+               
+               pPrt->PAutoNegFail = SK_TRUE;
+               pPrt->PMSStatus = SK_MS_STAT_FAULT;
+               
+               return(SK_HW_PS_RESTART);
+       }
+
+       /* Read PHY Specific Status */
+       SkGmPhyRead(pAC, IoC, Port, PHY_MARV_PHY_STAT, &PhySpecStat);
+       
+       SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+               ("Phy1000BT: 0x%04X, PhySpecStat: 0x%04X\n", ResAb, PhySpecStat));
+
+#ifdef DEBUG
+       SkGmPhyRead(pAC, IoC, Port, PHY_MARV_AUNE_EXP, &Word);
+
+       if ((PhyIsrc & PHY_M_IS_AN_PR) != 0 || (Word & PHY_ANE_RX_PG) != 0 ||
+               (PhySpecStat & PHY_M_PS_PAGE_REC) != 0)  {
+               /* Read PHY Next Page Link Partner */
+               SkGmPhyRead(pAC, IoC, Port, PHY_MARV_NEPG_LP, &Word);
+
+               SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+                       ("Page Received, NextPage: 0x%04X\n", Word));
+       }
+#endif /* DEBUG */
+
+       if ((PhySpecStat & PHY_M_PS_LINK_UP) == 0) {
+               return(SK_HW_PS_NONE);
+       }
+       
+       if ((PhySpecStat & PHY_M_PS_DOWNS_STAT) != 0 ||
+               (PhyIsrc & PHY_M_IS_DOWNSH_DET) != 0) {
+               /* Downshift detected */
+               SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_SIRQ_E025, SKERR_SIRQ_E025MSG);
+               
+               Para.Para64 = Port;
+               SkEventQueue(pAC, SKGE_DRV, SK_DRV_DOWNSHIFT_DET, Para);
+               
+               SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+                       ("Downshift detected, PhyIsrc: 0x%04X\n", PhyIsrc));
+       }
+
+       pPrt->PMSStatus = ((ResAb & PHY_B_1000S_MSR) != 0) ?
+               SK_MS_STAT_MASTER : SK_MS_STAT_SLAVE;
+       
+       pPrt->PCableLen = (SK_U8)((PhySpecStat & PHY_M_PS_CABLE_MSK) >> 7);
+       
+       if (AutoNeg) {
+               /* Auto-Negotiation Over ? */
+               if ((PhyStat & PHY_ST_AN_OVER) != 0) {
+                       
+                       SkHWLinkUp(pAC, IoC, Port);
+                       
+                       Done = SkMacAutoNegDone(pAC, IoC, Port);
+                       
+                       if (Done != SK_AND_OK) {
+                               return(SK_HW_PS_RESTART);
+                       }
+                       
+                       return(SK_HW_PS_LINK);
+               }
+       }
+       else {  /* !AutoNeg */
+               /* Link is up and we don't need more */
+#ifdef DEBUG
+               if (pPrt->PLipaAutoNeg == SK_LIPA_AUTO) {
+                       SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+                               ("ERROR: Lipa auto detected on port %d\n", Port));
+               }
+#endif /* DEBUG */
+
+               SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ,
+                       ("Link sync, Port %d\n", Port));
+               SkHWLinkUp(pAC, IoC, Port);
+               
+               return(SK_HW_PS_LINK);
+       }
+
+       return(SK_HW_PS_NONE);
+}      /* SkGePortCheckUpGmac */
+#endif /* YUKON */
+
+
+#ifdef OTHER_PHY
+/******************************************************************************
+ *
+ * SkGePortCheckUpLone() - Check if the link is up on Level One PHY
+ *
+ * return:
+ *     0       o.k. nothing needed
+ *     1       Restart needed on this port
+ *     2       Link came up
+ */
+static int SkGePortCheckUpLone(
+SK_AC  *pAC,           /* Adapter Context */
+SK_IOC IoC,            /* IO Context */
+int            Port,           /* Which port should be checked */
+SK_BOOL        AutoNeg)        /* Is Auto-negotiation used ? */
+{
+       SK_GEPORT       *pPrt;          /* GIni Port struct pointer */
+       int                     Done;
+       SK_U16          Isrc;           /* Interrupt source register */
+       SK_U16          LpAb;           /* Link Partner Ability */
+       SK_U16          ExtStat;        /* Extended Status Register */
+       SK_U16          PhyStat;        /* Phy Status Register */
+       SK_U16          StatSum;
+       SK_U8           NextMode;       /* Next AutoSensing Mode */
+
+       pPrt = &pAC->GIni.GP[Port];
+
+       if (pPrt->PHWLinkUp) {
+               return(SK_HW_PS_NONE);
+       }
+
+       StatSum = pPrt->PIsave;
+       pPrt->PIsave = 0;
+
+       /*
+        * here we usually can check whether the link is in sync and
+        * auto-negotiation is done.
+        */
+       SkXmPhyRead(pAC, IoC, Port, PHY_LONE_STAT, &PhyStat);
+       StatSum |= PhyStat;
+
+       SkMacAutoNegLipaPhy(pAC, IoC, Port, PhyStat);
+       
+       if ((PhyStat & PHY_ST_LSYNC) == 0) {
+               /* Save Auto-negotiation Done bit */
+               pPrt->PIsave = (SK_U16)(StatSum & PHY_ST_AN_OVER);
+#ifdef DEBUG
+               if ((pPrt->PIsave & PHY_ST_AN_OVER) != 0) {
+                       SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+                               ("AutoNeg done rescheduled Port %d\n", Port));
+               }
+#endif /* DEBUG */
+               return(SK_HW_PS_NONE);
+       }
+
+       if (AutoNeg) {
+               if ((StatSum & PHY_ST_AN_OVER) != 0) {
+                       SkHWLinkUp(pAC, IoC, Port);
+                       Done = SkMacAutoNegDone(pAC, IoC, Port);
+                       if (Done != SK_AND_OK) {
+                               /* Get PHY parameters, for debugging only */
+                               SkXmPhyRead(pAC, IoC, Port, PHY_LONE_AUNE_LP, &LpAb);
+                               SkXmPhyRead(pAC, IoC, Port, PHY_LONE_1000T_STAT, &ExtStat);
+                               SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+                                       ("AutoNeg FAIL Port %d (LpAb %x, 1000TStat %x)\n",
+                                        Port, LpAb, ExtStat));
+                                       
+                               /* Try next possible mode */
+                               NextMode = SkHWSenseGetNext(pAC, IoC, Port);
+                               SkHWLinkDown(pAC, IoC, Port);
+                               if (Done == SK_AND_DUP_CAP) {
+                                       /* GoTo next mode */
+                                       SkHWSenseSetNext(pAC, IoC, Port, NextMode);
+                               }
+
+                               return(SK_HW_PS_RESTART);
+
+                       }
+                       else {
+                               /*
+                                * Dummy Read interrupt status to prevent
+                                * extra link down/ups
+                                */
+                               SkXmPhyRead(pAC, IoC, Port, PHY_LONE_INT_STAT, &ExtStat);
+                               return(SK_HW_PS_LINK);
+                       }
+               }
+               
+               /* AutoNeg not done, but HW link is up. Check for timeouts */
+               pPrt->PAutoNegTimeOut++;
+               if (pPrt->PAutoNegTimeOut >= SK_AND_MAX_TO) {
+                       /* Timeout occured */
+                       SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ,
+                               ("AutoNeg timeout Port %d\n", Port));
+                       if (pPrt->PLinkModeConf == SK_LMODE_AUTOSENSE &&
+                               pPrt->PLipaAutoNeg != SK_LIPA_AUTO) {
+                               /* Set Link manually up */
+                               SkHWSenseSetNext(pAC, IoC, Port, SK_LMODE_FULL);
+                               SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ,
+                                       ("Set manual full duplex Port %d\n", Port));
+                       }
+
+                       /* Do the restart */
+                       return(SK_HW_PS_RESTART);
+               }
+       }
+       else {
+               /* Link is up and we don't need more */
+#ifdef DEBUG
+               if (pPrt->PLipaAutoNeg == SK_LIPA_AUTO) {
+                       SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+                               ("ERROR: Lipa auto detected on port %d\n", Port));
+               }
+#endif /* DEBUG */
+
+               /*
+                * Dummy Read interrupt status to prevent
+                * extra link down/ups
+                */
+               SkXmPhyRead(pAC, IoC, Port, PHY_LONE_INT_STAT, &ExtStat);
+               
+               SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ,
+                       ("Link sync(GP), Port %d\n", Port));
+               SkHWLinkUp(pAC, IoC, Port);
+               
+               return(SK_HW_PS_LINK);
+       }
+
+       return(SK_HW_PS_NONE);
+}      /* SkGePortCheckUpLone */
+
+
+/******************************************************************************
+ *
+ * SkGePortCheckUpNat() - Check if the link is up on National PHY
+ *
+ * return:
+ *     0       o.k. nothing needed
+ *     1       Restart needed on this port
+ *     2       Link came up
+ */
+static int SkGePortCheckUpNat(
+SK_AC  *pAC,           /* Adapter Context */
+SK_IOC IoC,            /* IO Context */
+int            Port,           /* Which port should be checked */
+SK_BOOL        AutoNeg)        /* Is Auto-negotiation used ? */
+{
+       /* todo: National */
+       return(SK_HW_PS_NONE);
+}      /* SkGePortCheckUpNat */
+#endif /* OTHER_PHY */
+
+
+/******************************************************************************
+ *
+ *     SkGeSirqEvent() - Event Service Routine
+ *
+ * Description:
+ *
+ * Notes:
+ */
+int    SkGeSirqEvent(
+SK_AC          *pAC,           /* Adapter Context */
+SK_IOC         IoC,            /* Io Context */
+SK_U32         Event,          /* Module specific Event */
+SK_EVPARA      Para)           /* Event specific Parameter */
+{
+       SK_GEPORT       *pPrt;          /* GIni Port struct pointer */
+       SK_U32          Port;
+       SK_U32          Val32;
+       int                     PortStat;
+       SK_U8           Val8;
+#ifdef GENESIS
+       SK_U64          Octets;
+#endif /* GENESIS */
+
+       Port = Para.Para32[0];
+       pPrt = &pAC->GIni.GP[Port];
+
+       switch (Event) {
+       case SK_HWEV_WATIM:
+               if (pPrt->PState == SK_PRT_RESET) {
+               
+                       PortStat = SK_HW_PS_NONE;
+               }
+               else {
+                       /* Check whether port came up */
+                       PortStat = SkGePortCheckUp(pAC, IoC, (int)Port);
+               }
+
+               switch (PortStat) {
+               case SK_HW_PS_RESTART:
+                       if (pPrt->PHWLinkUp) {
+                               /* Set Link to down */
+                               SkHWLinkDown(pAC, IoC, (int)Port);
+
+                               /*
+                                * Signal directly to RLMT to ensure correct
+                                * sequence of SWITCH and RESET event.
+                                */
+                               SkRlmtEvent(pAC, IoC, SK_RLMT_LINK_DOWN, Para);
+                       }
+
+                       /* Restart needed */
+                       SkEventQueue(pAC, SKGE_DRV, SK_DRV_PORT_RESET, Para);
+                       break;
+
+               case SK_HW_PS_LINK:
+                       /* Signal to RLMT */
+                       SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_LINK_UP, Para);
+                       break;
+               }
+               
+               /* Start again the check Timer */
+               if (pPrt->PHWLinkUp) {
+                       Val32 = SK_WA_ACT_TIME;
+               }
+               else {
+                       Val32 = SK_WA_INA_TIME;
+               }
+
+               /* Todo: still needed for non-XMAC PHYs??? */
+               /* Start workaround Errata #2 timer */
+               SkTimerStart(pAC, IoC, &pPrt->PWaTimer, Val32,
+                       SKGE_HWAC, SK_HWEV_WATIM, Para);
+               break;
+
+       case SK_HWEV_PORT_START:
+               if (pPrt->PHWLinkUp) {
+                       /*
+                        * Signal directly to RLMT to ensure correct
+                        * sequence of SWITCH and RESET event.
+                        */
+                       SkRlmtEvent(pAC, IoC, SK_RLMT_LINK_DOWN, Para);
+               }
+
+               SkHWLinkDown(pAC, IoC, (int)Port);
+
+               /* Schedule Port RESET */
+               SkEventQueue(pAC, SKGE_DRV, SK_DRV_PORT_RESET, Para);
+
+               /* Start workaround Errata #2 timer */
+               SkTimerStart(pAC, IoC, &pPrt->PWaTimer, SK_WA_INA_TIME,
+                       SKGE_HWAC, SK_HWEV_WATIM, Para);
+               break;
+
+       case SK_HWEV_PORT_STOP:
+               if (pPrt->PHWLinkUp) {
+                       /*
+                        * Signal directly to RLMT to ensure correct
+                        * sequence of SWITCH and RESET event.
+                        */
+                       SkRlmtEvent(pAC, IoC, SK_RLMT_LINK_DOWN, Para);
+               }
+
+               /* Stop Workaround Timer */
+               SkTimerStop(pAC, IoC, &pPrt->PWaTimer);
+
+               SkHWLinkDown(pAC, IoC, (int)Port);
+               break;
+
+       case SK_HWEV_UPDATE_STAT:
+               /* We do NOT need to update any statistics */
+               break;
+
+       case SK_HWEV_CLEAR_STAT:
+               /* We do NOT need to clear any statistics */
+               for (Port = 0; Port < (SK_U32)pAC->GIni.GIMacsFound; Port++) {
+                       pPrt->PPrevRx = 0;
+                       pPrt->PPrevFcs = 0;
+                       pPrt->PPrevShorts = 0;
+               }
+               break;
+
+       case SK_HWEV_SET_LMODE:
+               Val8 = (SK_U8)Para.Para32[1];
+               if (pPrt->PLinkModeConf != Val8) {
+                       /* Set New link mode */
+                       pPrt->PLinkModeConf = Val8;
+
+                       /* Restart Port */
+                       SkEventQueue(pAC, SKGE_HWAC, SK_HWEV_PORT_STOP, Para);
+                       SkEventQueue(pAC, SKGE_HWAC, SK_HWEV_PORT_START, Para);
+               }
+               break;
+
+       case SK_HWEV_SET_FLOWMODE:
+               Val8 = (SK_U8)Para.Para32[1];
+               if (pPrt->PFlowCtrlMode != Val8) {
+                       /* Set New Flow Control mode */
+                       pPrt->PFlowCtrlMode = Val8;
+
+                       /* Restart Port */
+                       SkEventQueue(pAC, SKGE_HWAC, SK_HWEV_PORT_STOP, Para);
+                       SkEventQueue(pAC, SKGE_HWAC, SK_HWEV_PORT_START, Para);
+               }
+               break;
+
+       case SK_HWEV_SET_ROLE:
+               /* not possible for fiber */
+               if (!pAC->GIni.GICopperType) {
+                       break;
+               }
+               Val8 = (SK_U8)Para.Para32[1];
+               if (pPrt->PMSMode != Val8) {
+                       /* Set New Role (Master/Slave) mode */
+                       pPrt->PMSMode = Val8;
+
+                       /* Restart Port */
+                       SkEventQueue(pAC, SKGE_HWAC, SK_HWEV_PORT_STOP, Para);
+                       SkEventQueue(pAC, SKGE_HWAC, SK_HWEV_PORT_START, Para);
+               }
+               break;
+
+       case SK_HWEV_SET_SPEED:
+               if (pPrt->PhyType != SK_PHY_MARV_COPPER) {
+                       break;
+               }
+               Val8 = (SK_U8)Para.Para32[1];
+               if (pPrt->PLinkSpeed != Val8) {
+                       /* Set New Speed parameter */
+                       pPrt->PLinkSpeed = Val8;
+
+                       /* Restart Port */
+                       SkEventQueue(pAC, SKGE_HWAC, SK_HWEV_PORT_STOP, Para);
+                       SkEventQueue(pAC, SKGE_HWAC, SK_HWEV_PORT_START, Para);
+               }
+               break;
+
+#ifdef GENESIS
+       case SK_HWEV_HALFDUP_CHK:
+               if (pAC->GIni.GIGenesis) {
+                       /*
+                        * half duplex hangup workaround.
+                        * See packet arbiter timeout interrupt for description
+                        */
+                       pPrt->HalfDupTimerActive = SK_FALSE;
+                       if (pPrt->PLinkModeStatus == SK_LMODE_STAT_HALF ||
+                               pPrt->PLinkModeStatus == SK_LMODE_STAT_AUTOHALF) {
+                               /* Snap statistic counters */
+                               (void)SkXmUpdateStats(pAC, IoC, Port);
+
+                               (void)SkXmMacStatistic(pAC, IoC, Port, XM_TXO_OK_HI, &Val32);
+
+                               Octets = (SK_U64)Val32 << 32;
+                               
+                               (void)SkXmMacStatistic(pAC, IoC, Port, XM_TXO_OK_LO, &Val32);
+
+                               Octets += Val32;
+                               
+                               if (pPrt->LastOctets == Octets) {
+                                       /* Tx hanging, a FIFO flush restarts it */
+                                       SkMacFlushTxFifo(pAC, IoC, Port);
+                               }
+                       }
+               }
+               break;
+#endif /* GENESIS */
+       
+       default:
+               SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_SIRQ_E001, SKERR_SIRQ_E001MSG);
+               break;
+       }
+
+       return(0);
+}      /* SkGeSirqEvent */
+
+
+#ifdef GENESIS
+/******************************************************************************
+ *
+ *     SkPhyIsrBcom() - PHY interrupt service routine
+ *
+ * Description: handles all interrupts from BCom PHY
+ *
+ * Returns: N/A
+ */
+static void SkPhyIsrBcom(
+SK_AC          *pAC,           /* Adapter Context */
+SK_IOC         IoC,            /* Io Context */
+int                    Port,           /* Port Num = PHY Num */
+SK_U16         IStatus)        /* Interrupt Status */
+{
+       SK_GEPORT       *pPrt;          /* GIni Port struct pointer */
+       SK_EVPARA       Para;
+
+       pPrt = &pAC->GIni.GP[Port];
+
+       if ((IStatus & PHY_B_IS_PSE) != 0) {
+               /* Incorrectable pair swap error */
+               SK_ERR_LOG(pAC, SK_ERRCL_HW | SK_ERRCL_INIT, SKERR_SIRQ_E022,
+                       SKERR_SIRQ_E022MSG);
+       }
+       
+       if ((IStatus & (PHY_B_IS_AN_PR | PHY_B_IS_LST_CHANGE)) != 0) {
+
+               SkHWLinkDown(pAC, IoC, Port);
+
+               Para.Para32[0] = (SK_U32)Port;
+               /* Signal to RLMT */
+               SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_LINK_DOWN, Para);
+
+               /* Start workaround Errata #2 timer */
+               SkTimerStart(pAC, IoC, &pPrt->PWaTimer, SK_WA_INA_TIME,
+                       SKGE_HWAC, SK_HWEV_WATIM, Para);
+       }
+
+}      /* SkPhyIsrBcom */
+#endif /* GENESIS */
+
+
+#ifdef YUKON
+/******************************************************************************
+ *
+ *     SkPhyIsrGmac() - PHY interrupt service routine
+ *
+ * Description: handles all interrupts from Marvell PHY
+ *
+ * Returns: N/A
+ */
+static void SkPhyIsrGmac(
+SK_AC          *pAC,           /* Adapter Context */
+SK_IOC         IoC,            /* Io Context */
+int                    Port,           /* Port Num = PHY Num */
+SK_U16         IStatus)        /* Interrupt Status */
+{
+       SK_GEPORT       *pPrt;          /* GIni Port struct pointer */
+       SK_EVPARA       Para;
+       SK_U16          Word;
+
+       pPrt = &pAC->GIni.GP[Port];
+
+       if ((IStatus & (PHY_M_IS_AN_PR | PHY_M_IS_LST_CHANGE)) != 0) {
+
+               SkHWLinkDown(pAC, IoC, Port);
+
+               SkGmPhyRead(pAC, IoC, Port, PHY_MARV_AUNE_ADV, &Word);
+
+               SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+                       ("AutoNeg.Adv: 0x%04X\n", Word));
+               
+               /* Set Auto-negotiation advertisement */
+               if (pPrt->PFlowCtrlMode == SK_FLOW_MODE_SYM_OR_REM) {
+                       /* restore Asymmetric Pause bit */
+                       SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_AUNE_ADV,
+                               (SK_U16)(Word | PHY_M_AN_ASP));
+               }
+               
+               Para.Para32[0] = (SK_U32)Port;
+               /* Signal to RLMT */
+               SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_LINK_DOWN, Para);
+       }
+       
+       if ((IStatus & PHY_M_IS_AN_ERROR) != 0) {
+               /* Auto-Negotiation Error */
+               SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_SIRQ_E023, SKERR_SIRQ_E023MSG);
+       }
+       
+       if ((IStatus & PHY_M_IS_FIFO_ERROR) != 0) {
+               /* FIFO Overflow/Underrun Error */
+               SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_SIRQ_E024, SKERR_SIRQ_E024MSG);
+       }
+       
+}      /* SkPhyIsrGmac */
+#endif /* YUKON */
+
+
+#ifdef OTHER_PHY
+/******************************************************************************
+ *
+ *     SkPhyIsrLone() - PHY interrupt service routine
+ *
+ * Description: handles all interrupts from LONE PHY
+ *
+ * Returns: N/A
+ */
+static void SkPhyIsrLone(
+SK_AC  *pAC,           /* Adapter Context */
+SK_IOC IoC,            /* Io Context */
+int            Port,           /* Port Num = PHY Num */
+SK_U16 IStatus)        /* Interrupt Status */
+{
+       SK_EVPARA       Para;
+
+       if (IStatus & (PHY_L_IS_DUP | PHY_L_IS_ISOL)) {
+               
+               SkHWLinkDown(pAC, IoC, Port);
+
+               Para.Para32[0] = (SK_U32)Port;
+               /* Signal to RLMT */
+               SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_LINK_DOWN, Para);
+       }
+
+}      /* SkPhyIsrLone */
+#endif /* OTHER_PHY */
+
+/* End of File */
diff --git a/drivers/net/sk98lin/ski2c.c b/drivers/net/sk98lin/ski2c.c
new file mode 100644 (file)
index 0000000..79bf57c
--- /dev/null
@@ -0,0 +1,1296 @@
+/******************************************************************************
+ *
+ * Name:       ski2c.c
+ * Project:    Gigabit Ethernet Adapters, TWSI-Module
+ * Version:    $Revision: 1.59 $
+ * Date:       $Date: 2003/10/20 09:07:25 $
+ * Purpose:    Functions to access Voltage and Temperature Sensor
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *     (C)Copyright 1998-2002 SysKonnect.
+ *     (C)Copyright 2002-2003 Marvell.
+ *
+ *     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.
+ *
+ *     The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/*
+ *     I2C Protocol
+ */
+#if (defined(DEBUG) || ((!defined(LINT)) && (!defined(SK_SLIM))))
+static const char SysKonnectFileId[] =
+       "@(#) $Id: ski2c.c,v 1.59 2003/10/20 09:07:25 rschmidt Exp $ (C) Marvell. ";
+#endif
+
+#include "h/skdrv1st.h"                /* Driver Specific Definitions */
+#include "h/lm80.h"
+#include "h/skdrv2nd.h"                /* Adapter Control- and Driver specific Def. */
+
+#ifdef __C2MAN__
+/*
+       I2C protocol implementation.
+
+       General Description:
+
+       The I2C protocol is used for the temperature sensors and for
+       the serial EEPROM which hold the configuration.
+
+       This file covers functions that allow to read write and do
+       some bulk requests a specified I2C address.
+
+       The Genesis has 2 I2C buses. One for the EEPROM which holds
+       the VPD Data and one for temperature and voltage sensor.
+       The following picture shows the I2C buses, I2C devices and
+       their control registers.
+
+       Note: The VPD functions are in skvpd.c
+.
+.      PCI Config I2C Bus for VPD Data:
+.
+.                    +------------+
+.                    | VPD EEPROM |
+.                    +------------+
+.                           |
+.                           | <-- I2C
+.                           |
+.               +-----------+-----------+
+.               |                       |
+.      +-----------------+     +-----------------+
+.      | PCI_VPD_ADR_REG |     | PCI_VPD_DAT_REG |
+.      +-----------------+     +-----------------+
+.
+.
+.      I2C Bus for LM80 sensor:
+.
+.                      +-----------------+
+.                      | Temperature and |
+.                      | Voltage Sensor  |
+.                      |       LM80      |
+.                      +-----------------+
+.                              |
+.                              |
+.                      I2C --> |
+.                              |
+.                           +----+
+.           +-------------->| OR |<--+
+.           |               +----+   |
+.     +------+------+                |
+.     |                    |                 |
+. +--------+   +--------+      +----------+
+. | B2_I2C |   | B2_I2C |      |  B2_I2C  |
+. | _CTRL  |   | _DATA  |      |   _SW    |
+. +--------+   +--------+      +----------+
+.
+       The I2C bus may be driven by the B2_I2C_SW or by the B2_I2C_CTRL
+       and B2_I2C_DATA registers.
+       For driver software it is recommended to use the I2C control and
+       data register, because I2C bus timing is done by the ASIC and
+       an interrupt may be received when the I2C request is completed.
+
+       Clock Rate Timing:                      MIN     MAX     generated by
+               VPD EEPROM:                     50 kHz  100 kHz         HW
+               LM80 over I2C Ctrl/Data reg.    50 kHz  100 kHz         HW
+               LM80 over B2_I2C_SW register    0       400 kHz         SW
+
+       Note:   The clock generated by the hardware is dependend on the
+               PCI clock. If the PCI bus clock is 33 MHz, the I2C/VPD
+               clock is 50 kHz.
+ */
+intro()
+{}
+#endif
+
+#ifdef SK_DIAG
+/*
+ * I2C Fast Mode timing values used by the LM80.
+ * If new devices are added to the I2C bus the timing values have to be checked.
+ */
+#ifndef I2C_SLOW_TIMING
+#define        T_CLK_LOW                       1300L   /* clock low time in ns */
+#define        T_CLK_HIGH                       600L   /* clock high time in ns */
+#define T_DATA_IN_SETUP                 100L   /* data in Set-up Time */
+#define T_START_HOLD            600L   /* start condition hold time */
+#define T_START_SETUP           600L   /* start condition Set-up time */
+#define        T_STOP_SETUP             600L   /* stop condition Set-up time */
+#define T_BUS_IDLE                     1300L   /* time the bus must free after Tx */
+#define        T_CLK_2_DATA_OUT         900L   /* max. clock low to data output valid */
+#else  /* I2C_SLOW_TIMING */
+/* I2C Standard Mode Timing */
+#define        T_CLK_LOW                       4700L   /* clock low time in ns */
+#define        T_CLK_HIGH                      4000L   /* clock high time in ns */
+#define T_DATA_IN_SETUP                 250L   /* data in Set-up Time */
+#define T_START_HOLD           4000L   /* start condition hold time */
+#define T_START_SETUP          4700L   /* start condition Set-up time */
+#define        T_STOP_SETUP            4000L   /* stop condition Set-up time */
+#define T_BUS_IDLE                     4700L   /* time the bus must free after Tx */
+#endif /* !I2C_SLOW_TIMING */
+
+#define NS2BCLK(x)     (((x)*125)/10000)
+
+/*
+ * I2C Wire Operations
+ *
+ * About I2C_CLK_LOW():
+ *
+ * The Data Direction bit (I2C_DATA_DIR) has to be set to input when setting
+ * clock to low, to prevent the ASIC and the I2C data client from driving the
+ * serial data line simultaneously (ASIC: last bit of a byte = '1', I2C client
+ * send an 'ACK'). See also Concentrator Bugreport No. 10192.
+ */
+#define I2C_DATA_HIGH(IoC)     SK_I2C_SET_BIT(IoC, I2C_DATA)
+#define        I2C_DATA_LOW(IoC)       SK_I2C_CLR_BIT(IoC, I2C_DATA)
+#define        I2C_DATA_OUT(IoC)       SK_I2C_SET_BIT(IoC, I2C_DATA_DIR)
+#define        I2C_DATA_IN(IoC)        SK_I2C_CLR_BIT(IoC, I2C_DATA_DIR | I2C_DATA)
+#define        I2C_CLK_HIGH(IoC)       SK_I2C_SET_BIT(IoC, I2C_CLK)
+#define        I2C_CLK_LOW(IoC)        SK_I2C_CLR_BIT(IoC, I2C_CLK | I2C_DATA_DIR)
+#define        I2C_START_COND(IoC)     SK_I2C_CLR_BIT(IoC, I2C_CLK)
+
+#define NS2CLKT(x)     ((x*125L)/10000)
+
+/*--------------- I2C Interface Register Functions --------------- */
+
+/*
+ * sending one bit
+ */
+void SkI2cSndBit(
+SK_IOC IoC,    /* I/O Context */
+SK_U8  Bit)    /* Bit to send */
+{
+       I2C_DATA_OUT(IoC);
+       if (Bit) {
+               I2C_DATA_HIGH(IoC);
+       }
+       else {
+               I2C_DATA_LOW(IoC);
+       }
+       SkDgWaitTime(IoC, NS2BCLK(T_DATA_IN_SETUP));
+       I2C_CLK_HIGH(IoC);
+       SkDgWaitTime(IoC, NS2BCLK(T_CLK_HIGH));
+       I2C_CLK_LOW(IoC);
+}      /* SkI2cSndBit*/
+
+
+/*
+ * Signal a start to the I2C Bus.
+ *
+ * A start is signaled when data goes to low in a high clock cycle.
+ *
+ * Ends with Clock Low.
+ *
+ * Status: not tested
+ */
+void SkI2cStart(
+SK_IOC IoC)    /* I/O Context */
+{
+       /* Init data and Clock to output lines */
+       /* Set Data high */
+       I2C_DATA_OUT(IoC);
+       I2C_DATA_HIGH(IoC);
+       /* Set Clock high */
+       I2C_CLK_HIGH(IoC);
+
+       SkDgWaitTime(IoC, NS2BCLK(T_START_SETUP));
+
+       /* Set Data Low */
+       I2C_DATA_LOW(IoC);
+
+       SkDgWaitTime(IoC, NS2BCLK(T_START_HOLD));
+
+       /* Clock low without Data to Input */
+       I2C_START_COND(IoC);
+
+       SkDgWaitTime(IoC, NS2BCLK(T_CLK_LOW));
+}      /* SkI2cStart */
+
+
+void SkI2cStop(
+SK_IOC IoC)    /* I/O Context */
+{
+       /* Init data and Clock to output lines */
+       /* Set Data low */
+       I2C_DATA_OUT(IoC);
+       I2C_DATA_LOW(IoC);
+
+       SkDgWaitTime(IoC, NS2BCLK(T_CLK_2_DATA_OUT));
+
+       /* Set Clock high */
+       I2C_CLK_HIGH(IoC);
+
+       SkDgWaitTime(IoC, NS2BCLK(T_STOP_SETUP));
+
+       /*
+        * Set Data High:       Do it by setting the Data Line to Input.
+        *                      Because of a pull up resistor the Data Line
+        *                      floods to high.
+        */
+       I2C_DATA_IN(IoC);
+
+       /*
+        *      When I2C activity is stopped
+        *       o      DATA should be set to input and
+        *       o      CLOCK should be set to high!
+        */
+       SkDgWaitTime(IoC, NS2BCLK(T_BUS_IDLE));
+}      /* SkI2cStop */
+
+
+/*
+ * Receive just one bit via the I2C bus.
+ *
+ * Note:       Clock must be set to LOW before calling this function.
+ *
+ * Returns The received bit.
+ */
+int SkI2cRcvBit(
+SK_IOC IoC)    /* I/O Context */
+{
+       int     Bit;
+       SK_U8   I2cSwCtrl;
+
+       /* Init data as input line */
+       I2C_DATA_IN(IoC);
+
+       SkDgWaitTime(IoC, NS2BCLK(T_CLK_2_DATA_OUT));
+
+       I2C_CLK_HIGH(IoC);
+
+       SkDgWaitTime(IoC, NS2BCLK(T_CLK_HIGH));
+
+       SK_I2C_GET_SW(IoC, &I2cSwCtrl);
+       
+       Bit = (I2cSwCtrl & I2C_DATA) ? 1 : 0;
+
+       I2C_CLK_LOW(IoC);
+       SkDgWaitTime(IoC, NS2BCLK(T_CLK_LOW-T_CLK_2_DATA_OUT));
+
+       return(Bit);
+}      /* SkI2cRcvBit */
+
+
+/*
+ * Receive an ACK.
+ *
+ * returns     0 If acknowledged
+ *             1 in case of an error
+ */
+int SkI2cRcvAck(
+SK_IOC IoC)    /* I/O Context */
+{
+       /*
+        * Received bit must be zero.
+        */
+       return(SkI2cRcvBit(IoC) != 0);
+}      /* SkI2cRcvAck */
+
+
+/*
+ * Send an NACK.
+ */
+void SkI2cSndNAck(
+SK_IOC IoC)    /* I/O Context */
+{
+       /*
+        * Received bit must be zero.
+        */
+       SkI2cSndBit(IoC, 1);
+}      /* SkI2cSndNAck */
+
+
+/*
+ * Send an ACK.
+ */
+void SkI2cSndAck(
+SK_IOC IoC)    /* I/O Context */
+{
+       /*
+        * Received bit must be zero.
+        */
+       SkI2cSndBit(IoC, 0);
+}      /* SkI2cSndAck */
+
+
+/*
+ * Send one byte to the I2C device and wait for ACK.
+ *
+ * Return acknowleged status.
+ */
+int SkI2cSndByte(
+SK_IOC IoC,    /* I/O Context */
+int            Byte)   /* byte to send */
+{
+       int     i;
+
+       for (i = 0; i < 8; i++) {
+               if (Byte & (1<<(7-i))) {
+                       SkI2cSndBit(IoC, 1);
+               }
+               else {
+                       SkI2cSndBit(IoC, 0);
+               }
+       }
+
+       return(SkI2cRcvAck(IoC));
+}      /* SkI2cSndByte */
+
+
+/*
+ * Receive one byte and ack it.
+ *
+ * Return byte.
+ */
+int SkI2cRcvByte(
+SK_IOC IoC,    /* I/O Context */
+int            Last)   /* Last Byte Flag */
+{
+       int     i;
+       int     Byte = 0;
+
+       for (i = 0; i < 8; i++) {
+               Byte <<= 1;
+               Byte |= SkI2cRcvBit(IoC);
+       }
+
+       if (Last) {
+               SkI2cSndNAck(IoC);
+       }
+       else {
+               SkI2cSndAck(IoC);
+       }
+
+       return(Byte);
+}      /* SkI2cRcvByte */
+
+
+/*
+ * Start dialog and send device address
+ *
+ * Return 0 if acknowleged, 1 in case of an error
+ */
+int    SkI2cSndDev(
+SK_IOC IoC,    /* I/O Context */
+int            Addr,   /* Device Address */
+int            Rw)             /* Read / Write Flag */
+{
+       SkI2cStart(IoC);
+       Rw = ~Rw;
+       Rw &= I2C_WRITE;
+       return(SkI2cSndByte(IoC, (Addr<<1) | Rw));
+}      /* SkI2cSndDev */
+
+#endif /* SK_DIAG */
+
+/*----------------- I2C CTRL Register Functions ----------*/
+
+/*
+ * waits for a completion of an I2C transfer
+ *
+ * returns     0:      success, transfer completes
+ *                     1:      error,   transfer does not complete, I2C transfer
+ *                                              killed, wait loop terminated.
+ */
+static int     SkI2cWait(
+SK_AC  *pAC,   /* Adapter Context */
+SK_IOC IoC,    /* I/O Context */
+int            Event)  /* complete event to wait for (I2C_READ or I2C_WRITE) */
+{
+       SK_U64  StartTime;
+       SK_U64  CurrentTime;
+       SK_U32  I2cCtrl;
+
+       StartTime = SkOsGetTime(pAC);
+       
+       do {
+               CurrentTime = SkOsGetTime(pAC);
+
+               if (CurrentTime - StartTime > SK_TICKS_PER_SEC / 8) {
+                       
+                       SK_I2C_STOP(IoC);
+#ifndef SK_DIAG
+                       SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_I2C_E002, SKERR_I2C_E002MSG);
+#endif /* !SK_DIAG */
+                       return(1);
+               }
+               
+               SK_I2C_GET_CTL(IoC, &I2cCtrl);
+
+#ifdef xYUKON_DBG
+               printf("StartTime=%lu, CurrentTime=%lu\n",
+                       StartTime, CurrentTime);
+               if (kbhit()) {
+                       return(1);
+               }
+#endif /* YUKON_DBG */
+       
+       } while ((I2cCtrl & I2C_FLAG) == (SK_U32)Event << 31);
+
+       return(0);
+}      /* SkI2cWait */
+
+
+/*
+ * waits for a completion of an I2C transfer
+ *
+ * Returns
+ *     Nothing
+ */
+void SkI2cWaitIrq(
+SK_AC  *pAC,   /* Adapter Context */
+SK_IOC IoC)    /* I/O Context */
+{
+       SK_SENSOR       *pSen;
+       SK_U64          StartTime;
+       SK_U32          IrqSrc;
+
+       pSen = &pAC->I2c.SenTable[pAC->I2c.CurrSens];
+
+       if (pSen->SenState == SK_SEN_IDLE) {
+               return;
+       }
+
+       StartTime = SkOsGetTime(pAC);
+       
+       do {
+               if (SkOsGetTime(pAC) - StartTime > SK_TICKS_PER_SEC / 8) {
+                       
+                       SK_I2C_STOP(IoC);
+#ifndef SK_DIAG
+                       SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_I2C_E016, SKERR_I2C_E016MSG);
+#endif /* !SK_DIAG */
+                       return;
+               }
+               
+               SK_IN32(IoC, B0_ISRC, &IrqSrc);
+
+       } while ((IrqSrc & IS_I2C_READY) == 0);
+
+       pSen->SenState = SK_SEN_IDLE;
+       return;
+}      /* SkI2cWaitIrq */
+
+/*
+ * writes a single byte or 4 bytes into the I2C device
+ *
+ * returns     0:      success
+ *                     1:      error
+ */
+static int SkI2cWrite(
+SK_AC  *pAC,           /* Adapter Context */
+SK_IOC IoC,            /* I/O Context */
+SK_U32 I2cData,        /* I2C Data to write */
+int            I2cDev,         /* I2C Device Address */
+int            I2cDevSize, /* I2C Device Size (e.g. I2C_025K_DEV or I2C_2K_DEV) */
+int            I2cReg,         /* I2C Device Register Address */
+int            I2cBurst)       /* I2C Burst Flag */
+{
+       SK_OUT32(IoC, B2_I2C_DATA, I2cData);
+       
+       SK_I2C_CTL(IoC, I2C_WRITE, I2cDev, I2cDevSize, I2cReg, I2cBurst);
+       
+       return(SkI2cWait(pAC, IoC, I2C_WRITE));
+}      /* SkI2cWrite*/
+
+
+#ifdef SK_DIAG
+/*
+ * reads a single byte or 4 bytes from the I2C device
+ *
+ * returns     the word read
+ */
+SK_U32 SkI2cRead(
+SK_AC  *pAC,           /* Adapter Context */
+SK_IOC IoC,            /* I/O Context */
+int            I2cDev,         /* I2C Device Address */
+int            I2cDevSize, /* I2C Device Size (e.g. I2C_025K_DEV or I2C_2K_DEV) */
+int            I2cReg,         /* I2C Device Register Address */
+int            I2cBurst)       /* I2C Burst Flag */
+{
+       SK_U32  Data;
+
+       SK_OUT32(IoC, B2_I2C_DATA, 0);
+       SK_I2C_CTL(IoC, I2C_READ, I2cDev, I2cDevSize, I2cReg, I2cBurst);
+       
+       if (SkI2cWait(pAC, IoC, I2C_READ) != 0) {
+               w_print("%s\n", SKERR_I2C_E002MSG);
+       }
+       
+       SK_IN32(IoC, B2_I2C_DATA, &Data);
+       
+       return(Data);
+}      /* SkI2cRead */
+#endif /* SK_DIAG */
+
+
+/*
+ * read a sensor's value
+ *
+ * This function reads a sensor's value from the I2C sensor chip. The sensor
+ * is defined by its index into the sensors database in the struct pAC points
+ * to.
+ * Returns
+ *             1 if the read is completed
+ *             0 if the read must be continued (I2C Bus still allocated)
+ */
+static int     SkI2cReadSensor(
+SK_AC          *pAC,   /* Adapter Context */
+SK_IOC         IoC,    /* I/O Context */
+SK_SENSOR      *pSen)  /* Sensor to be read */
+{
+    if (pSen->SenRead != NULL) {
+        return((*pSen->SenRead)(pAC, IoC, pSen));
+    }
+       else {
+        return(0); /* no success */
+       }
+}      /* SkI2cReadSensor */
+
+/*
+ * Do the Init state 0 initialization
+ */
+static int SkI2cInit0(
+SK_AC  *pAC)   /* Adapter Context */
+{
+       int     i;
+
+       /* Begin with first sensor */
+       pAC->I2c.CurrSens = 0;
+       
+       /* Begin with timeout control for state machine */
+       pAC->I2c.TimerMode = SK_TIMER_WATCH_SM;
+       
+       /* Set sensor number to zero */
+       pAC->I2c.MaxSens = 0;
+
+#ifndef SK_DIAG
+       /* Initialize Number of Dummy Reads */
+       pAC->I2c.DummyReads = SK_MAX_SENSORS;
+#endif
+
+       for (i = 0; i < SK_MAX_SENSORS; i++) {
+               pAC->I2c.SenTable[i].SenDesc = "unknown";
+               pAC->I2c.SenTable[i].SenType = SK_SEN_UNKNOWN;
+               pAC->I2c.SenTable[i].SenThreErrHigh = 0;
+               pAC->I2c.SenTable[i].SenThreErrLow = 0;
+               pAC->I2c.SenTable[i].SenThreWarnHigh = 0;
+               pAC->I2c.SenTable[i].SenThreWarnLow = 0;
+               pAC->I2c.SenTable[i].SenReg = LM80_FAN2_IN;
+               pAC->I2c.SenTable[i].SenInit = SK_SEN_DYN_INIT_NONE;
+               pAC->I2c.SenTable[i].SenValue = 0;
+               pAC->I2c.SenTable[i].SenErrFlag = SK_SEN_ERR_NOT_PRESENT;
+               pAC->I2c.SenTable[i].SenErrCts = 0;
+               pAC->I2c.SenTable[i].SenBegErrTS = 0;
+               pAC->I2c.SenTable[i].SenState = SK_SEN_IDLE;
+               pAC->I2c.SenTable[i].SenRead = NULL;
+               pAC->I2c.SenTable[i].SenDev = 0;
+       }
+
+       /* Now we are "INIT data"ed */
+       pAC->I2c.InitLevel = SK_INIT_DATA;
+       return(0);
+}      /* SkI2cInit0*/
+
+
+/*
+ * Do the init state 1 initialization
+ *
+ * initialize the following register of the LM80:
+ * Configuration register:
+ * - START, noINT, activeLOW, noINT#Clear, noRESET, noCI, noGPO#, noINIT
+ *
+ * Interrupt Mask Register 1:
+ * - all interrupts are Disabled (0xff)
+ *
+ * Interrupt Mask Register 2:
+ * - all interrupts are Disabled (0xff) Interrupt modi doesn't matter.
+ *
+ * Fan Divisor/RST_OUT register:
+ * - Divisors set to 1 (bits 00), all others 0s.
+ *
+ * OS# Configuration/Temperature resolution Register:
+ * - all 0s
+ *
+ */
+static int SkI2cInit1(
+SK_AC  *pAC,   /* Adapter Context */
+SK_IOC IoC)    /* I/O Context */
+{
+    int i;
+    SK_U8 I2cSwCtrl;
+       SK_GEPORT *pPrt;        /* GIni Port struct pointer */
+
+       if (pAC->I2c.InitLevel != SK_INIT_DATA) {
+               /* ReInit not needed in I2C module */
+               return(0);
+       }
+
+    /* Set the Direction of I2C-Data Pin to IN */
+    SK_I2C_CLR_BIT(IoC, I2C_DATA_DIR | I2C_DATA);
+    /* Check for 32-Bit Yukon with Low at I2C-Data Pin */
+       SK_I2C_GET_SW(IoC, &I2cSwCtrl);
+
+       if ((I2cSwCtrl & I2C_DATA) == 0) {
+               /* this is a 32-Bit board */
+               pAC->GIni.GIYukon32Bit = SK_TRUE;
+        return(0);
+    }
+
+       /* Check for 64 Bit Yukon without sensors */
+       if (SkI2cWrite(pAC, IoC, 0, LM80_ADDR, I2C_025K_DEV, LM80_CFG, 0) != 0) {
+        return(0);
+    }
+
+       (void)SkI2cWrite(pAC, IoC, 0xffUL, LM80_ADDR, I2C_025K_DEV, LM80_IMSK_1, 0);
+       
+       (void)SkI2cWrite(pAC, IoC, 0xffUL, LM80_ADDR, I2C_025K_DEV, LM80_IMSK_2, 0);
+       
+       (void)SkI2cWrite(pAC, IoC, 0, LM80_ADDR, I2C_025K_DEV, LM80_FAN_CTRL, 0);
+       
+       (void)SkI2cWrite(pAC, IoC, 0, LM80_ADDR, I2C_025K_DEV, LM80_TEMP_CTRL, 0);
+       
+       (void)SkI2cWrite(pAC, IoC, (SK_U32)LM80_CFG_START, LM80_ADDR, I2C_025K_DEV,
+               LM80_CFG, 0);
+       
+       /*
+        * MaxSens has to be updated here, because PhyType is not
+        * set when performing Init Level 0
+        */
+    pAC->I2c.MaxSens = 5;
+       
+       pPrt = &pAC->GIni.GP[0];
+       
+       if (pAC->GIni.GIGenesis) {
+               if (pPrt->PhyType == SK_PHY_BCOM) {
+                       if (pAC->GIni.GIMacsFound == 1) {
+                               pAC->I2c.MaxSens += 1;
+                       }
+                       else {
+                               pAC->I2c.MaxSens += 3;
+                       }
+               }
+       }
+       else {
+               pAC->I2c.MaxSens += 3;
+       }
+       
+       for (i = 0; i < pAC->I2c.MaxSens; i++) {
+               switch (i) {
+               case 0:
+                       pAC->I2c.SenTable[i].SenDesc = "Temperature";
+                       pAC->I2c.SenTable[i].SenType = SK_SEN_TEMP;
+                       pAC->I2c.SenTable[i].SenThreErrHigh = SK_SEN_TEMP_HIGH_ERR;
+                       pAC->I2c.SenTable[i].SenThreWarnHigh = SK_SEN_TEMP_HIGH_WARN;
+                       pAC->I2c.SenTable[i].SenThreWarnLow = SK_SEN_TEMP_LOW_WARN;
+                       pAC->I2c.SenTable[i].SenThreErrLow = SK_SEN_TEMP_LOW_ERR;
+                       pAC->I2c.SenTable[i].SenReg = LM80_TEMP_IN;
+                       break;
+               case 1:
+                       pAC->I2c.SenTable[i].SenDesc = "Voltage PCI";
+                       pAC->I2c.SenTable[i].SenType = SK_SEN_VOLT;
+                       pAC->I2c.SenTable[i].SenThreErrHigh = SK_SEN_PCI_5V_HIGH_ERR;
+                       pAC->I2c.SenTable[i].SenThreWarnHigh = SK_SEN_PCI_5V_HIGH_WARN;
+                       pAC->I2c.SenTable[i].SenThreWarnLow = SK_SEN_PCI_5V_LOW_WARN;
+                       pAC->I2c.SenTable[i].SenThreErrLow = SK_SEN_PCI_5V_LOW_ERR;
+                       pAC->I2c.SenTable[i].SenReg = LM80_VT0_IN;
+                       break;
+               case 2:
+                       pAC->I2c.SenTable[i].SenDesc = "Voltage PCI-IO";
+                       pAC->I2c.SenTable[i].SenType = SK_SEN_VOLT;
+                       pAC->I2c.SenTable[i].SenThreErrHigh = SK_SEN_PCI_IO_5V_HIGH_ERR;
+                       pAC->I2c.SenTable[i].SenThreWarnHigh = SK_SEN_PCI_IO_5V_HIGH_WARN;
+                       pAC->I2c.SenTable[i].SenThreWarnLow = SK_SEN_PCI_IO_3V3_LOW_WARN;
+                       pAC->I2c.SenTable[i].SenThreErrLow = SK_SEN_PCI_IO_3V3_LOW_ERR;
+                       pAC->I2c.SenTable[i].SenReg = LM80_VT1_IN;
+                       pAC->I2c.SenTable[i].SenInit = SK_SEN_DYN_INIT_PCI_IO;
+                       break;
+               case 3:
+                       pAC->I2c.SenTable[i].SenDesc = "Voltage ASIC";
+                       pAC->I2c.SenTable[i].SenType = SK_SEN_VOLT;
+                       pAC->I2c.SenTable[i].SenThreErrHigh = SK_SEN_VDD_HIGH_ERR;
+                       pAC->I2c.SenTable[i].SenThreWarnHigh = SK_SEN_VDD_HIGH_WARN;
+                       pAC->I2c.SenTable[i].SenThreWarnLow = SK_SEN_VDD_LOW_WARN;
+                       pAC->I2c.SenTable[i].SenThreErrLow = SK_SEN_VDD_LOW_ERR;
+                       pAC->I2c.SenTable[i].SenReg = LM80_VT2_IN;
+                       break;
+               case 4:
+                       if (pAC->GIni.GIGenesis) {
+                               if (pPrt->PhyType == SK_PHY_BCOM) {
+                                       pAC->I2c.SenTable[i].SenDesc = "Voltage PHY A PLL";
+                                       pAC->I2c.SenTable[i].SenThreErrHigh = SK_SEN_PLL_3V3_HIGH_ERR;
+                                       pAC->I2c.SenTable[i].SenThreWarnHigh = SK_SEN_PLL_3V3_HIGH_WARN;
+                                       pAC->I2c.SenTable[i].SenThreWarnLow = SK_SEN_PLL_3V3_LOW_WARN;
+                                       pAC->I2c.SenTable[i].SenThreErrLow = SK_SEN_PLL_3V3_LOW_ERR;
+                               }
+                               else {
+                                       pAC->I2c.SenTable[i].SenDesc = "Voltage PMA";
+                                       pAC->I2c.SenTable[i].SenThreErrHigh = SK_SEN_PLL_3V3_HIGH_ERR;
+                                       pAC->I2c.SenTable[i].SenThreWarnHigh = SK_SEN_PLL_3V3_HIGH_WARN;
+                                       pAC->I2c.SenTable[i].SenThreWarnLow = SK_SEN_PLL_3V3_LOW_WARN;
+                                       pAC->I2c.SenTable[i].SenThreErrLow = SK_SEN_PLL_3V3_LOW_ERR;
+                               }
+                       }
+                       else {
+                               pAC->I2c.SenTable[i].SenDesc = "Voltage VAUX";
+                               pAC->I2c.SenTable[i].SenThreErrHigh = SK_SEN_VAUX_3V3_HIGH_ERR;
+                               pAC->I2c.SenTable[i].SenThreWarnHigh = SK_SEN_VAUX_3V3_HIGH_WARN;
+                               if (pAC->GIni.GIVauxAvail) {
+                                       pAC->I2c.SenTable[i].SenThreWarnLow = SK_SEN_VAUX_3V3_LOW_WARN;
+                                       pAC->I2c.SenTable[i].SenThreErrLow = SK_SEN_VAUX_3V3_LOW_ERR;
+                               }
+                               else {
+                                       pAC->I2c.SenTable[i].SenThreErrLow = SK_SEN_VAUX_0V_WARN_ERR;
+                                       pAC->I2c.SenTable[i].SenThreWarnLow = SK_SEN_VAUX_0V_WARN_ERR;
+                               }
+                       }
+                       pAC->I2c.SenTable[i].SenType = SK_SEN_VOLT;
+                       pAC->I2c.SenTable[i].SenReg = LM80_VT3_IN;
+                       break;
+               case 5:
+                       if (pAC->GIni.GIGenesis) {
+                               pAC->I2c.SenTable[i].SenDesc = "Voltage PHY 2V5";
+                               pAC->I2c.SenTable[i].SenThreErrHigh = SK_SEN_PHY_2V5_HIGH_ERR;
+                               pAC->I2c.SenTable[i].SenThreWarnHigh = SK_SEN_PHY_2V5_HIGH_WARN;
+                               pAC->I2c.SenTable[i].SenThreWarnLow = SK_SEN_PHY_2V5_LOW_WARN;
+                               pAC->I2c.SenTable[i].SenThreErrLow = SK_SEN_PHY_2V5_LOW_ERR;
+                       }
+                       else {
+                               pAC->I2c.SenTable[i].SenDesc = "Voltage Core 1V5";
+                               pAC->I2c.SenTable[i].SenThreErrHigh = SK_SEN_CORE_1V5_HIGH_ERR;
+                               pAC->I2c.SenTable[i].SenThreWarnHigh = SK_SEN_CORE_1V5_HIGH_WARN;
+                               pAC->I2c.SenTable[i].SenThreWarnLow = SK_SEN_CORE_1V5_LOW_WARN;
+                               pAC->I2c.SenTable[i].SenThreErrLow = SK_SEN_CORE_1V5_LOW_ERR;
+                       }
+                       pAC->I2c.SenTable[i].SenType = SK_SEN_VOLT;
+                       pAC->I2c.SenTable[i].SenReg = LM80_VT4_IN;
+                       break;
+               case 6:
+                       if (pAC->GIni.GIGenesis) {
+                               pAC->I2c.SenTable[i].SenDesc = "Voltage PHY B PLL";
+                       }
+                       else {
+                               pAC->I2c.SenTable[i].SenDesc = "Voltage PHY 3V3";
+                       }
+                       pAC->I2c.SenTable[i].SenType = SK_SEN_VOLT;
+                       pAC->I2c.SenTable[i].SenThreErrHigh = SK_SEN_PLL_3V3_HIGH_ERR;
+                       pAC->I2c.SenTable[i].SenThreWarnHigh = SK_SEN_PLL_3V3_HIGH_WARN;
+                       pAC->I2c.SenTable[i].SenThreWarnLow = SK_SEN_PLL_3V3_LOW_WARN;
+                       pAC->I2c.SenTable[i].SenThreErrLow = SK_SEN_PLL_3V3_LOW_ERR;
+                       pAC->I2c.SenTable[i].SenReg = LM80_VT5_IN;
+                       break;
+               case 7:
+                       if (pAC->GIni.GIGenesis) {
+                               pAC->I2c.SenTable[i].SenDesc = "Speed Fan";
+                               pAC->I2c.SenTable[i].SenType = SK_SEN_FAN;
+                               pAC->I2c.SenTable[i].SenThreErrHigh = SK_SEN_FAN_HIGH_ERR;
+                               pAC->I2c.SenTable[i].SenThreWarnHigh = SK_SEN_FAN_HIGH_WARN;
+                               pAC->I2c.SenTable[i].SenThreWarnLow = SK_SEN_FAN_LOW_WARN;
+                               pAC->I2c.SenTable[i].SenThreErrLow = SK_SEN_FAN_LOW_ERR;
+                               pAC->I2c.SenTable[i].SenReg = LM80_FAN2_IN;
+                       }
+                       else {
+                               pAC->I2c.SenTable[i].SenDesc = "Voltage PHY 2V5";
+                               pAC->I2c.SenTable[i].SenType = SK_SEN_VOLT;
+                               pAC->I2c.SenTable[i].SenThreErrHigh = SK_SEN_PHY_2V5_HIGH_ERR;
+                               pAC->I2c.SenTable[i].SenThreWarnHigh = SK_SEN_PHY_2V5_HIGH_WARN;
+                               pAC->I2c.SenTable[i].SenThreWarnLow = SK_SEN_PHY_2V5_LOW_WARN;
+                               pAC->I2c.SenTable[i].SenThreErrLow = SK_SEN_PHY_2V5_LOW_ERR;
+                               pAC->I2c.SenTable[i].SenReg = LM80_VT6_IN;
+                       }
+                       break;
+               default:
+                       SK_ERR_LOG(pAC, SK_ERRCL_INIT | SK_ERRCL_SW,
+                               SKERR_I2C_E001, SKERR_I2C_E001MSG);
+                       break;
+               }
+
+               pAC->I2c.SenTable[i].SenValue = 0;
+               pAC->I2c.SenTable[i].SenErrFlag = SK_SEN_ERR_OK;
+               pAC->I2c.SenTable[i].SenErrCts = 0;
+               pAC->I2c.SenTable[i].SenBegErrTS = 0;
+               pAC->I2c.SenTable[i].SenState = SK_SEN_IDLE;
+               pAC->I2c.SenTable[i].SenRead = SkLm80ReadSensor;
+               pAC->I2c.SenTable[i].SenDev = LM80_ADDR;
+       }
+
+#ifndef SK_DIAG
+       pAC->I2c.DummyReads = pAC->I2c.MaxSens;
+#endif /* !SK_DIAG */
+       
+       /* Clear I2C IRQ */
+       SK_OUT32(IoC, B2_I2C_IRQ, I2C_CLR_IRQ);
+       
+       /* Now we are I/O initialized */
+       pAC->I2c.InitLevel = SK_INIT_IO;
+       return(0);
+}      /* SkI2cInit1 */
+
+
+/*
+ * Init level 2: Start first sensor read.
+ */
+static int SkI2cInit2(
+SK_AC  *pAC,   /* Adapter Context */
+SK_IOC IoC)    /* I/O Context */
+{
+       int             ReadComplete;
+       SK_SENSOR       *pSen;
+
+       if (pAC->I2c.InitLevel != SK_INIT_IO) {
+               /* ReInit not needed in I2C module */
+               /* Init0 and Init2 not permitted */
+               return(0);
+       }
+
+       pSen = &pAC->I2c.SenTable[pAC->I2c.CurrSens];
+       ReadComplete = SkI2cReadSensor(pAC, IoC, pSen);
+
+       if (ReadComplete) {
+               SK_ERR_LOG(pAC, SK_ERRCL_INIT, SKERR_I2C_E008, SKERR_I2C_E008MSG);
+       }
+
+       /* Now we are correctly initialized */
+       pAC->I2c.InitLevel = SK_INIT_RUN;
+
+       return(0);
+}      /* SkI2cInit2*/
+
+
+/*
+ * Initialize I2C devices
+ *
+ * Get the first voltage value and discard it.
+ * Go into temperature read mode. A default pointer is not set.
+ *
+ * The things to be done depend on the init level in the parameter list:
+ * Level 0:
+ *     Initialize only the data structures. Do NOT access hardware.
+ * Level 1:
+ *     Initialize hardware through SK_IN / SK_OUT commands. Do NOT use interrupts.
+ * Level 2:
+ *     Everything is possible. Interrupts may be used from now on.
+ *
+ * return:
+ *     0 = success
+ *     other = error.
+ */
+int    SkI2cInit(
+SK_AC  *pAC,   /* Adapter Context */
+SK_IOC IoC,    /* I/O Context needed in levels 1 and 2 */
+int            Level)  /* Init Level */
+{
+
+       switch (Level) {
+       case SK_INIT_DATA:
+               return(SkI2cInit0(pAC));
+       case SK_INIT_IO:
+               return(SkI2cInit1(pAC, IoC));
+       case SK_INIT_RUN:
+               return(SkI2cInit2(pAC, IoC));
+       default:
+               break;
+       }
+
+       return(0);
+}      /* SkI2cInit */
+
+
+#ifndef SK_DIAG
+
+/*
+ * Interrupt service function for the I2C Interface
+ *
+ * Clears the Interrupt source
+ *
+ * Reads the register and check it for sending a trap.
+ *
+ * Starts the timer if necessary.
+ */
+void SkI2cIsr(
+SK_AC  *pAC,   /* Adapter Context */
+SK_IOC IoC)    /* I/O Context */
+{
+       SK_EVPARA       Para;
+
+       /* Clear I2C IRQ */
+       SK_OUT32(IoC, B2_I2C_IRQ, I2C_CLR_IRQ);
+
+       Para.Para64 = 0;
+       SkEventQueue(pAC, SKGE_I2C, SK_I2CEV_IRQ, Para);
+}      /* SkI2cIsr */
+
+
+/*
+ * Check this sensors Value against the threshold and send events.
+ */
+static void SkI2cCheckSensor(
+SK_AC          *pAC,   /* Adapter Context */
+SK_SENSOR      *pSen)
+{
+       SK_EVPARA       ParaLocal;
+       SK_BOOL         TooHigh;        /* Is sensor too high? */
+       SK_BOOL         TooLow;         /* Is sensor too low? */
+       SK_U64          CurrTime;       /* Current Time */
+       SK_BOOL         DoTrapSend;     /* We need to send a trap */
+       SK_BOOL         DoErrLog;       /* We need to log the error */
+       SK_BOOL         IsError;        /* We need to log the error */
+
+       /* Check Dummy Reads first */
+       if (pAC->I2c.DummyReads > 0) {
+               pAC->I2c.DummyReads--;
+               return;
+       }
+
+       /* Get the current time */
+       CurrTime = SkOsGetTime(pAC);
+
+       /* Set para to the most useful setting: The current sensor. */
+       ParaLocal.Para64 = (SK_U64)pAC->I2c.CurrSens;
+
+       /* Check the Value against the thresholds. First: Error Thresholds */
+       TooHigh = (pSen->SenValue > pSen->SenThreErrHigh);
+       TooLow = (pSen->SenValue < pSen->SenThreErrLow);
+               
+       IsError = SK_FALSE;
+       if (TooHigh || TooLow) {
+               /* Error condition is satisfied */
+               DoTrapSend = SK_TRUE;
+               DoErrLog = SK_TRUE;
+
+               /* Now error condition is satisfied */
+               IsError = SK_TRUE;
+
+               if (pSen->SenErrFlag == SK_SEN_ERR_ERR) {
+                       /* This state is the former one */
+
+                       /* So check first whether we have to send a trap */
+                       if (pSen->SenLastErrTrapTS + SK_SEN_ERR_TR_HOLD >
+                           CurrTime) {
+                               /*
+                                * Do NOT send the Trap. The hold back time
+                                * has to run out first.
+                                */
+                               DoTrapSend = SK_FALSE;
+                       }
+
+                       /* Check now whether we have to log an Error */
+                       if (pSen->SenLastErrLogTS + SK_SEN_ERR_LOG_HOLD >
+                           CurrTime) {
+                               /*
+                                * Do NOT log the error. The hold back time
+                                * has to run out first.
+                                */
+                               DoErrLog = SK_FALSE;
+                       }
+               }
+               else {
+                       /* We came from a different state -> Set Begin Time Stamp */
+                       pSen->SenBegErrTS = CurrTime;
+                       pSen->SenErrFlag = SK_SEN_ERR_ERR;
+               }
+
+               if (DoTrapSend) {
+                       /* Set current Time */
+                       pSen->SenLastErrTrapTS = CurrTime;
+                       pSen->SenErrCts++;
+
+                       /* Queue PNMI Event */
+                       SkEventQueue(pAC, SKGE_PNMI, (TooHigh ?
+                               SK_PNMI_EVT_SEN_ERR_UPP :
+                               SK_PNMI_EVT_SEN_ERR_LOW),
+                               ParaLocal);
+               }
+
+               if (DoErrLog) {
+                       /* Set current Time */
+                       pSen->SenLastErrLogTS = CurrTime;
+
+                       if (pSen->SenType == SK_SEN_TEMP) {
+                               SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_I2C_E011, SKERR_I2C_E011MSG);
+                       }
+                       else if (pSen->SenType == SK_SEN_VOLT) {
+                               SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_I2C_E012, SKERR_I2C_E012MSG);
+                       }
+                       else {
+                               SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_I2C_E015, SKERR_I2C_E015MSG);
+                       }
+               }
+       }
+
+       /* Check the Value against the thresholds */
+       /* 2nd: Warning thresholds */
+       TooHigh = (pSen->SenValue > pSen->SenThreWarnHigh);
+       TooLow = (pSen->SenValue < pSen->SenThreWarnLow);
+               
+       if (!IsError && (TooHigh || TooLow)) {
+               /* Error condition is satisfied */
+               DoTrapSend = SK_TRUE;
+               DoErrLog = SK_TRUE;
+
+               if (pSen->SenErrFlag == SK_SEN_ERR_WARN) {
+                       /* This state is the former one */
+
+                       /* So check first whether we have to send a trap */
+                       if (pSen->SenLastWarnTrapTS + SK_SEN_WARN_TR_HOLD > CurrTime) {
+                               /*
+                                * Do NOT send the Trap. The hold back time
+                                * has to run out first.
+                                */
+                               DoTrapSend = SK_FALSE;
+                       }
+
+                       /* Check now whether we have to log an Error */
+                       if (pSen->SenLastWarnLogTS + SK_SEN_WARN_LOG_HOLD > CurrTime) {
+                               /*
+                                * Do NOT log the error. The hold back time
+                                * has to run out first.
+                                */
+                               DoErrLog = SK_FALSE;
+                       }
+               }
+               else {
+                       /* We came from a different state -> Set Begin Time Stamp */
+                       pSen->SenBegWarnTS = CurrTime;
+                       pSen->SenErrFlag = SK_SEN_ERR_WARN;
+               }
+
+               if (DoTrapSend) {
+                       /* Set current Time */
+                       pSen->SenLastWarnTrapTS = CurrTime;
+                       pSen->SenWarnCts++;
+
+                       /* Queue PNMI Event */
+                       SkEventQueue(pAC, SKGE_PNMI, (TooHigh ?
+                               SK_PNMI_EVT_SEN_WAR_UPP :
+                               SK_PNMI_EVT_SEN_WAR_LOW),
+                               ParaLocal);
+               }
+
+               if (DoErrLog) {
+                       /* Set current Time */
+                       pSen->SenLastWarnLogTS = CurrTime;
+
+                       if (pSen->SenType == SK_SEN_TEMP) {
+                               SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_I2C_E009, SKERR_I2C_E009MSG);
+                       }
+                       else if (pSen->SenType == SK_SEN_VOLT) {
+                               SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_I2C_E010, SKERR_I2C_E010MSG);
+                       }
+                       else {
+                               SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_I2C_E014, SKERR_I2C_E014MSG);
+                       }
+               }
+       }
+
+       /* Check for NO error at all */
+       if (!IsError && !TooHigh && !TooLow) {
+               /* Set o.k. Status if no error and no warning condition */
+               pSen->SenErrFlag = SK_SEN_ERR_OK;
+       }
+
+       /* End of check against the thresholds */
+
+       /* Bug fix AF: 16.Aug.2001: Correct the init base
+        * of LM80 sensor.
+        */
+       if (pSen->SenInit == SK_SEN_DYN_INIT_PCI_IO) {
+
+        pSen->SenInit = SK_SEN_DYN_INIT_NONE;
+
+               if (pSen->SenValue > SK_SEN_PCI_IO_RANGE_LIMITER) {
+                       /* 5V PCI-IO Voltage */
+                       pSen->SenThreWarnLow = SK_SEN_PCI_IO_5V_LOW_WARN;
+                       pSen->SenThreErrLow = SK_SEN_PCI_IO_5V_LOW_ERR;
+               }
+               else {
+                       /* 3.3V PCI-IO Voltage */
+                       pSen->SenThreWarnHigh = SK_SEN_PCI_IO_3V3_HIGH_WARN;
+                       pSen->SenThreErrHigh = SK_SEN_PCI_IO_3V3_HIGH_ERR;
+               }
+       }
+       
+#ifdef TEST_ONLY
+    /* Dynamic thresholds also for VAUX of LM80 sensor */
+       if (pSen->SenInit == SK_SEN_DYN_INIT_VAUX) {
+
+        pSen->SenInit = SK_SEN_DYN_INIT_NONE;
+
+               /* 3.3V VAUX Voltage */
+               if (pSen->SenValue > SK_SEN_VAUX_RANGE_LIMITER) {
+                       pSen->SenThreWarnLow = SK_SEN_VAUX_3V3_LOW_WARN;
+                       pSen->SenThreErrLow = SK_SEN_VAUX_3V3_LOW_ERR;
+               }
+               /* 0V VAUX Voltage */
+               else {
+                       pSen->SenThreWarnHigh = SK_SEN_VAUX_0V_WARN_ERR;
+                       pSen->SenThreErrHigh = SK_SEN_VAUX_0V_WARN_ERR;
+               }
+       }
+
+       /*
+        * Check initialization state:
+        * The VIO Thresholds need adaption
+        */
+       if (!pSen->SenInit && pSen->SenReg == LM80_VT1_IN &&
+            pSen->SenValue > SK_SEN_WARNLOW2C &&
+            pSen->SenValue < SK_SEN_WARNHIGH2) {
+               pSen->SenThreErrLow = SK_SEN_ERRLOW2C;
+               pSen->SenThreWarnLow = SK_SEN_WARNLOW2C;
+               pSen->SenInit = SK_TRUE;
+       }
+
+       if (!pSen->SenInit && pSen->SenReg == LM80_VT1_IN &&
+            pSen->SenValue > SK_SEN_WARNLOW2 &&
+            pSen->SenValue < SK_SEN_WARNHIGH2C) {
+               pSen->SenThreErrHigh = SK_SEN_ERRHIGH2C;
+               pSen->SenThreWarnHigh = SK_SEN_WARNHIGH2C;
+               pSen->SenInit = SK_TRUE;
+       }
+#endif
+
+       if (pSen->SenInit != SK_SEN_DYN_INIT_NONE) {
+               SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_I2C_E013, SKERR_I2C_E013MSG);
+       }
+}      /* SkI2cCheckSensor */
+
+
+/*
+ * The only Event to be served is the timeout event
+ *
+ */
+int    SkI2cEvent(
+SK_AC          *pAC,   /* Adapter Context */
+SK_IOC         IoC,    /* I/O Context */
+SK_U32         Event,  /* Module specific Event */
+SK_EVPARA      Para)   /* Event specific Parameter */
+{
+       int                     ReadComplete;
+       SK_SENSOR       *pSen;
+       SK_U32          Time;
+       SK_EVPARA       ParaLocal;
+       int                     i;
+
+       /* New case: no sensors */
+       if (pAC->I2c.MaxSens == 0) {
+               return(0);
+       }
+
+       switch (Event) {
+       case SK_I2CEV_IRQ:
+               pSen = &pAC->I2c.SenTable[pAC->I2c.CurrSens];
+               ReadComplete = SkI2cReadSensor(pAC, IoC, pSen);
+
+               if (ReadComplete) {
+                       /* Check sensor against defined thresholds */
+                       SkI2cCheckSensor(pAC, pSen);
+
+                       /* Increment Current sensor and set appropriate Timeout */
+                       pAC->I2c.CurrSens++;
+                       if (pAC->I2c.CurrSens >= pAC->I2c.MaxSens) {
+                               pAC->I2c.CurrSens = 0;
+                               Time = SK_I2C_TIM_LONG;
+                       }
+                       else {
+                               Time = SK_I2C_TIM_SHORT;
+                       }
+
+                       /* Start Timer */
+                       ParaLocal.Para64 = (SK_U64)0;
+
+                       pAC->I2c.TimerMode = SK_TIMER_NEW_GAUGING;
+                       
+                       SkTimerStart(pAC, IoC, &pAC->I2c.SenTimer, Time,
+                               SKGE_I2C, SK_I2CEV_TIM, ParaLocal);
+               }
+        else {
+                       /* Start Timer */
+                       ParaLocal.Para64 = (SK_U64)0;
+
+                       pAC->I2c.TimerMode = SK_TIMER_WATCH_SM;
+
+            SkTimerStart(pAC, IoC, &pAC->I2c.SenTimer, SK_I2C_TIM_WATCH,
+                               SKGE_I2C, SK_I2CEV_TIM, ParaLocal);
+               }
+               break;
+       case SK_I2CEV_TIM:
+               if (pAC->I2c.TimerMode == SK_TIMER_NEW_GAUGING) {
+
+                       ParaLocal.Para64 = (SK_U64)0;
+                       SkTimerStop(pAC, IoC, &pAC->I2c.SenTimer);
+
+                       pSen = &pAC->I2c.SenTable[pAC->I2c.CurrSens];
+                       ReadComplete = SkI2cReadSensor(pAC, IoC, pSen);
+
+                       if (ReadComplete) {
+                               /* Check sensor against defined thresholds */
+                               SkI2cCheckSensor(pAC, pSen);
+
+                               /* Increment Current sensor and set appropriate Timeout */
+                               pAC->I2c.CurrSens++;
+                               if (pAC->I2c.CurrSens == pAC->I2c.MaxSens) {
+                                       pAC->I2c.CurrSens = 0;
+                                       Time = SK_I2C_TIM_LONG;
+                               }
+                               else {
+                                       Time = SK_I2C_TIM_SHORT;
+                               }
+
+                               /* Start Timer */
+                               ParaLocal.Para64 = (SK_U64)0;
+
+                               pAC->I2c.TimerMode = SK_TIMER_NEW_GAUGING;
+
+                               SkTimerStart(pAC, IoC, &pAC->I2c.SenTimer, Time,
+                                       SKGE_I2C, SK_I2CEV_TIM, ParaLocal);
+                       }
+               }
+               else {
+                       pSen = &pAC->I2c.SenTable[pAC->I2c.CurrSens];
+                       pSen->SenErrFlag = SK_SEN_ERR_FAULTY;
+                       SK_I2C_STOP(IoC);
+
+                       /* Increment Current sensor and set appropriate Timeout */
+                       pAC->I2c.CurrSens++;
+                       if (pAC->I2c.CurrSens == pAC->I2c.MaxSens) {
+                               pAC->I2c.CurrSens = 0;
+                               Time = SK_I2C_TIM_LONG;
+                       }
+                       else {
+                               Time = SK_I2C_TIM_SHORT;
+                       }
+
+                       /* Start Timer */
+                       ParaLocal.Para64 = (SK_U64)0;
+
+                       pAC->I2c.TimerMode = SK_TIMER_NEW_GAUGING;
+
+                       SkTimerStart(pAC, IoC, &pAC->I2c.SenTimer, Time,
+                               SKGE_I2C, SK_I2CEV_TIM, ParaLocal);
+               }
+               break;
+       case SK_I2CEV_CLEAR:
+               for (i = 0; i < SK_MAX_SENSORS; i++) {
+                       pAC->I2c.SenTable[i].SenErrFlag = SK_SEN_ERR_OK;
+                       pAC->I2c.SenTable[i].SenErrCts = 0;
+                       pAC->I2c.SenTable[i].SenWarnCts = 0;
+                       pAC->I2c.SenTable[i].SenBegErrTS = 0;
+                       pAC->I2c.SenTable[i].SenBegWarnTS = 0;
+                       pAC->I2c.SenTable[i].SenLastErrTrapTS = (SK_U64)0;
+                       pAC->I2c.SenTable[i].SenLastErrLogTS = (SK_U64)0;
+                       pAC->I2c.SenTable[i].SenLastWarnTrapTS = (SK_U64)0;
+                       pAC->I2c.SenTable[i].SenLastWarnLogTS = (SK_U64)0;
+               }
+               break;
+       default:
+               SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_I2C_E006, SKERR_I2C_E006MSG);
+       }
+
+       return(0);
+}      /* SkI2cEvent*/
+
+#endif /* !SK_DIAG */
diff --git a/drivers/net/sk98lin/sklm80.c b/drivers/net/sk98lin/sklm80.c
new file mode 100644 (file)
index 0000000..a204f5b
--- /dev/null
@@ -0,0 +1,141 @@
+/******************************************************************************
+ *
+ * Name:       sklm80.c
+ * Project:    Gigabit Ethernet Adapters, TWSI-Module
+ * Version:    $Revision: 1.22 $
+ * Date:       $Date: 2003/10/20 09:08:21 $
+ * Purpose:    Functions to access Voltage and Temperature Sensor (LM80)
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *     (C)Copyright 1998-2002 SysKonnect.
+ *     (C)Copyright 2002-2003 Marvell.
+ *
+ *     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.
+ *
+ *     The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/*
+       LM80 functions
+*/
+#if (defined(DEBUG) || ((!defined(LINT)) && (!defined(SK_SLIM))))
+static const char SysKonnectFileId[] =
+       "@(#) $Id: sklm80.c,v 1.22 2003/10/20 09:08:21 rschmidt Exp $ (C) Marvell. ";
+#endif
+
+#include "h/skdrv1st.h"                /* Driver Specific Definitions */
+#include "h/lm80.h"
+#include "h/skdrv2nd.h"                /* Adapter Control- and Driver specific Def. */
+
+#define        BREAK_OR_WAIT(pAC,IoC,Event)    break
+
+/*
+ * read a sensors value (LM80 specific)
+ *
+ * This function reads a sensors value from the I2C sensor chip LM80.
+ * The sensor is defined by its index into the sensors database in the struct
+ * pAC points to.
+ *
+ * Returns     1 if the read is completed
+ *             0 if the read must be continued (I2C Bus still allocated)
+ */
+int SkLm80ReadSensor(
+SK_AC          *pAC,   /* Adapter Context */
+SK_IOC         IoC,    /* I/O Context needed in level 1 and 2 */
+SK_SENSOR      *pSen)  /* Sensor to be read */
+{
+       SK_I32          Value;
+
+       switch (pSen->SenState) {
+       case SK_SEN_IDLE:
+               /* Send address to ADDR register */
+               SK_I2C_CTL(IoC, I2C_READ, pSen->SenDev, I2C_025K_DEV, pSen->SenReg, 0);
+
+               pSen->SenState = SK_SEN_VALUE ;
+               BREAK_OR_WAIT(pAC, IoC, I2C_READ);
+       
+       case SK_SEN_VALUE:
+               /* Read value from data register */
+               SK_IN32(IoC, B2_I2C_DATA, ((SK_U32 *)&Value));
+               
+               Value &= 0xff; /* only least significant byte is valid */
+
+               /* Do NOT check the Value against the thresholds */
+               /* Checking is done in the calling instance */
+
+               if (pSen->SenType == SK_SEN_VOLT) {
+                       /* Voltage sensor */
+                       pSen->SenValue = Value * SK_LM80_VT_LSB;
+                       pSen->SenState = SK_SEN_IDLE ;
+                       return(1);
+               }
+
+               if (pSen->SenType == SK_SEN_FAN) {
+                       if (Value != 0 && Value != 0xff) {
+                               /* Fan speed counter */
+                               pSen->SenValue = SK_LM80_FAN_FAKTOR/Value;
+                       }
+                       else {
+                               /* Indicate Fan error */
+                               pSen->SenValue = 0;
+                       }
+                       pSen->SenState = SK_SEN_IDLE ;
+                       return(1);
+               }
+
+               /* First: correct the value: it might be negative */
+               if ((Value & 0x80) != 0) {
+                       /* Value is negative */
+                       Value = Value - 256;
+               }
+
+               /* We have a temperature sensor and need to get the signed extension.
+                * For now we get the extension from the last reading, so in the normal
+                * case we won't see flickering temperatures.
+                */
+               pSen->SenValue = (Value * SK_LM80_TEMP_LSB) +
+                       (pSen->SenValue % SK_LM80_TEMP_LSB);
+
+               /* Send address to ADDR register */
+               SK_I2C_CTL(IoC, I2C_READ, pSen->SenDev, I2C_025K_DEV, LM80_TEMP_CTRL, 0);
+
+               pSen->SenState = SK_SEN_VALEXT ;
+               BREAK_OR_WAIT(pAC, IoC, I2C_READ);
+       
+       case SK_SEN_VALEXT:
+               /* Read value from data register */
+               SK_IN32(IoC, B2_I2C_DATA, ((SK_U32 *)&Value));
+               Value &= LM80_TEMP_LSB_9; /* only bit 7 is valid */
+
+               /* cut the LSB bit */
+               pSen->SenValue = ((pSen->SenValue / SK_LM80_TEMP_LSB) *
+                       SK_LM80_TEMP_LSB);
+
+               if (pSen->SenValue < 0) {
+                       /* Value negative: The bit value must be subtracted */
+                       pSen->SenValue -= ((Value >> 7) * SK_LM80_TEMPEXT_LSB);
+               }
+               else {
+                       /* Value positive: The bit value must be added */
+                       pSen->SenValue += ((Value >> 7) * SK_LM80_TEMPEXT_LSB);
+               }
+
+               pSen->SenState = SK_SEN_IDLE ;
+               return(1);
+       
+       default:
+               SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_I2C_E007, SKERR_I2C_E007MSG);
+               return(1);
+       }
+
+       /* Not completed */
+       return(0);
+}
+
diff --git a/drivers/net/sk98lin/skqueue.c b/drivers/net/sk98lin/skqueue.c
new file mode 100644 (file)
index 0000000..0275b4f
--- /dev/null
@@ -0,0 +1,179 @@
+/******************************************************************************
+ *
+ * Name:       skqueue.c
+ * Project:    Gigabit Ethernet Adapters, Event Scheduler Module
+ * Version:    $Revision: 1.20 $
+ * Date:       $Date: 2003/09/16 13:44:00 $
+ * Purpose:    Management of an event queue.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *     (C)Copyright 1998-2002 SysKonnect GmbH.
+ *     (C)Copyright 2002-2003 Marvell.
+ *
+ *     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.
+ *
+ *     The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+
+/*
+ *     Event queue and dispatcher
+ */
+#if (defined(DEBUG) || ((!defined(LINT)) && (!defined(SK_SLIM))))
+static const char SysKonnectFileId[] =
+       "@(#) $Id: skqueue.c,v 1.20 2003/09/16 13:44:00 rschmidt Exp $ (C) Marvell.";
+#endif
+
+#include "h/skdrv1st.h"                /* Driver Specific Definitions */
+#include "h/skqueue.h"         /* Queue Definitions */
+#include "h/skdrv2nd.h"                /* Adapter Control- and Driver specific Def. */
+
+#ifdef __C2MAN__
+/*
+       Event queue management.
+
+       General Description:
+
+ */
+intro()
+{}
+#endif
+
+#define PRINTF(a,b,c)
+
+/*
+ * init event queue management
+ *
+ * Must be called during init level 0.
+ */
+void   SkEventInit(
+SK_AC  *pAC,   /* Adapter context */
+SK_IOC Ioc,    /* IO context */
+int            Level)  /* Init level */
+{
+       switch (Level) {
+       case SK_INIT_DATA:
+               pAC->Event.EvPut = pAC->Event.EvGet = pAC->Event.EvQueue;
+               break;
+       default:
+               break;
+       }
+}
+
+/*
+ * add event to queue
+ */
+void   SkEventQueue(
+SK_AC          *pAC,   /* Adapters context */
+SK_U32         Class,  /* Event Class */
+SK_U32         Event,  /* Event to be queued */
+SK_EVPARA      Para)   /* Event parameter */
+{
+       pAC->Event.EvPut->Class = Class;
+       pAC->Event.EvPut->Event = Event;
+       pAC->Event.EvPut->Para = Para;
+       
+       if (++pAC->Event.EvPut == &pAC->Event.EvQueue[SK_MAX_EVENT])
+               pAC->Event.EvPut = pAC->Event.EvQueue;
+
+       if (pAC->Event.EvPut == pAC->Event.EvGet) {
+               SK_ERR_LOG(pAC, SK_ERRCL_NORES, SKERR_Q_E001, SKERR_Q_E001MSG);
+       }
+}
+
+/*
+ * event dispatcher
+ *     while event queue is not empty
+ *             get event from queue
+ *             send command to state machine
+ *     end
+ *     return error reported by individual Event function
+ *             0 if no error occured.
+ */
+int    SkEventDispatcher(
+SK_AC  *pAC,   /* Adapters Context */
+SK_IOC Ioc)    /* Io context */
+{
+       SK_EVENTELEM    *pEv;   /* pointer into queue */
+       SK_U32                  Class;
+       int                     Rtv;
+
+       pEv = pAC->Event.EvGet;
+       
+       PRINTF("dispatch get %x put %x\n", pEv, pAC->Event.ev_put);
+       
+       while (pEv != pAC->Event.EvPut) {
+               PRINTF("dispatch Class %d Event %d\n", pEv->Class, pEv->Event);
+
+               switch (Class = pEv->Class) {
+#ifndef SK_USE_LAC_EV
+#ifndef SK_SLIM
+               case SKGE_RLMT:         /* RLMT Event */
+                       Rtv = SkRlmtEvent(pAC, Ioc, pEv->Event, pEv->Para);
+                       break;
+               case SKGE_I2C:          /* I2C Event */
+                       Rtv = SkI2cEvent(pAC, Ioc, pEv->Event, pEv->Para);
+                       break;
+               case SKGE_PNMI:         /* PNMI Event */
+                       Rtv = SkPnmiEvent(pAC, Ioc, pEv->Event, pEv->Para);
+                       break;
+#endif /* not SK_SLIM */
+#endif /* not SK_USE_LAC_EV */
+               case SKGE_DRV:          /* Driver Event */
+                       Rtv = SkDrvEvent(pAC, Ioc, pEv->Event, pEv->Para);
+                       break;
+#ifndef SK_USE_SW_TIMER
+               case SKGE_HWAC:
+                       Rtv = SkGeSirqEvent(pAC, Ioc, pEv->Event, pEv->Para);
+                       break;
+#else /* !SK_USE_SW_TIMER */
+        case SKGE_SWT :
+                       Rtv = SkSwtEvent(pAC, Ioc, pEv->Event, pEv->Para);
+                       break;
+#endif /* !SK_USE_SW_TIMER */
+#ifdef SK_USE_LAC_EV
+               case SKGE_LACP :
+                       Rtv = SkLacpEvent(pAC, Ioc, pEv->Event, pEv->Para);
+                       break;
+               case SKGE_RSF :
+                       Rtv = SkRsfEvent(pAC, Ioc, pEv->Event, pEv->Para);
+                       break;
+               case SKGE_MARKER :
+                       Rtv = SkMarkerEvent(pAC, Ioc, pEv->Event, pEv->Para);
+                       break;
+               case SKGE_FD :
+                       Rtv = SkFdEvent(pAC, Ioc, pEv->Event, pEv->Para);
+                       break;
+#endif /* SK_USE_LAC_EV */
+#ifdef SK_USE_CSUM
+               case SKGE_CSUM :
+                       Rtv = SkCsEvent(pAC, Ioc, pEv->Event, pEv->Para);
+                       break;
+#endif /* SK_USE_CSUM */
+               default :
+                       SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_Q_E002, SKERR_Q_E002MSG);
+                       Rtv = 0;
+               }
+
+               if (Rtv != 0) {
+                       return(Rtv);
+               }
+
+               if (++pEv == &pAC->Event.EvQueue[SK_MAX_EVENT])
+                       pEv = pAC->Event.EvQueue;
+
+               /* Renew get: it is used in queue_events to detect overruns */
+               pAC->Event.EvGet = pEv;
+       }
+
+       return(0);
+}
+
+/* End of file */
diff --git a/drivers/net/sk98lin/skrlmt.c b/drivers/net/sk98lin/skrlmt.c
new file mode 100644 (file)
index 0000000..be8d1cc
--- /dev/null
@@ -0,0 +1,3257 @@
+/******************************************************************************
+ *
+ * Name:       skrlmt.c
+ * Project:    GEnesis, PCI Gigabit Ethernet Adapter
+ * Version:    $Revision: 1.69 $
+ * Date:       $Date: 2003/04/15 09:39:22 $
+ * Purpose:    Manage links on SK-NET Adapters, esp. redundant ones.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *     (C)Copyright 1998-2002 SysKonnect GmbH.
+ *     (C)Copyright 2002-2003 Marvell.
+ *
+ *     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.
+ *
+ *     The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * Description:
+ *
+ * This module contains code for Link ManagemenT (LMT) of SK-NET Adapters.
+ * It is mainly intended for adapters with more than one link.
+ * For such adapters, this module realizes Redundant Link ManagemenT (RLMT).
+ *
+ * Include File Hierarchy:
+ *
+ *     "skdrv1st.h"
+ *     "skdrv2nd.h"
+ *
+ ******************************************************************************/
+
+#ifndef        lint
+static const char SysKonnectFileId[] =
+       "@(#) $Id: skrlmt.c,v 1.69 2003/04/15 09:39:22 tschilli Exp $ (C) Marvell.";
+#endif /* !defined(lint) */
+
+#define __SKRLMT_C
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* cplusplus */
+
+#include "h/skdrv1st.h"
+#include "h/skdrv2nd.h"
+
+/* defines ********************************************************************/
+
+#ifndef SK_HWAC_LINK_LED
+#define SK_HWAC_LINK_LED(a,b,c,d)
+#endif /* !defined(SK_HWAC_LINK_LED) */
+
+#ifndef DEBUG
+#define RLMT_STATIC    static
+#else  /* DEBUG */
+#define RLMT_STATIC
+
+#ifndef SK_LITTLE_ENDIAN
+/* First 32 bits */
+#define OFFS_LO32      1
+
+/* Second 32 bits */
+#define OFFS_HI32      0
+#else  /* SK_LITTLE_ENDIAN */
+/* First 32 bits */
+#define OFFS_LO32      0
+
+/* Second 32 bits */
+#define OFFS_HI32      1
+#endif /* SK_LITTLE_ENDIAN */
+
+#endif /* DEBUG */
+
+/* ----- Private timeout values ----- */
+
+#define SK_RLMT_MIN_TO_VAL                        125000       /* 1/8 sec. */
+#define SK_RLMT_DEF_TO_VAL                       1000000       /* 1 sec. */
+#define SK_RLMT_PORTDOWN_TIM_VAL          900000       /* another 0.9 sec. */
+#define SK_RLMT_PORTSTART_TIM_VAL         100000       /* 0.1 sec. */
+#define SK_RLMT_PORTUP_TIM_VAL           2500000       /* 2.5 sec. */
+#define SK_RLMT_SEG_TO_VAL                     900000000       /* 15 min. */
+
+/* Assume tick counter increment is 1 - may be set OS-dependent. */
+#ifndef SK_TICK_INCR
+#define SK_TICK_INCR   SK_CONSTU64(1)
+#endif /* !defined(SK_TICK_INCR) */
+
+/*
+ * Amount that a time stamp must be later to be recognized as "substantially
+ * later". This is about 1/128 sec, but above 1 tick counter increment.
+ */
+#define SK_RLMT_BC_DELTA               (1 + ((SK_TICKS_PER_SEC >> 7) > SK_TICK_INCR ? \
+                                                                       (SK_TICKS_PER_SEC >> 7) : SK_TICK_INCR))
+
+/* ----- Private RLMT defaults ----- */
+
+#define SK_RLMT_DEF_PREF_PORT  0                                       /* "Lower" port. */
+#define SK_RLMT_DEF_MODE               SK_RLMT_CHECK_LINK      /* Default RLMT Mode. */
+
+/* ----- Private RLMT checking states ----- */
+
+#define SK_RLMT_RCS_SEG                        1               /* RLMT Check State: check seg. */
+#define SK_RLMT_RCS_START_SEG  2               /* RLMT Check State: start check seg. */
+#define SK_RLMT_RCS_SEND_SEG   4               /* RLMT Check State: send BPDU packet */
+#define SK_RLMT_RCS_REPORT_SEG 8               /* RLMT Check State: report seg. */
+
+/* ----- Private PORT checking states ----- */
+
+#define SK_RLMT_PCS_TX                 1               /* Port Check State: check tx. */
+#define SK_RLMT_PCS_RX                 2               /* Port Check State: check rx. */
+
+/* ----- Private PORT events ----- */
+
+/* Note: Update simulation when changing these. */
+#define SK_RLMT_PORTSTART_TIM  1100    /* Port start timeout. */
+#define SK_RLMT_PORTUP_TIM             1101    /* Port can now go up. */
+#define SK_RLMT_PORTDOWN_RX_TIM        1102    /* Port did not receive once ... */
+#define SK_RLMT_PORTDOWN               1103    /* Port went down. */
+#define SK_RLMT_PORTDOWN_TX_TIM        1104    /* Partner did not receive ... */
+
+/* ----- Private RLMT events ----- */
+
+/* Note: Update simulation when changing these. */
+#define SK_RLMT_TIM                            2100    /* RLMT timeout. */
+#define SK_RLMT_SEG_TIM                        2101    /* RLMT segmentation check timeout. */
+
+#define TO_SHORTEN(tim)        ((tim) / 2)
+
+/* Error numbers and messages. */
+#define SKERR_RLMT_E001                (SK_ERRBASE_RLMT + 0)
+#define SKERR_RLMT_E001_MSG    "No Packet."
+#define SKERR_RLMT_E002                (SKERR_RLMT_E001 + 1)
+#define SKERR_RLMT_E002_MSG    "Short Packet."
+#define SKERR_RLMT_E003                (SKERR_RLMT_E002 + 1)
+#define SKERR_RLMT_E003_MSG    "Unknown RLMT event."
+#define SKERR_RLMT_E004                (SKERR_RLMT_E003 + 1)
+#define SKERR_RLMT_E004_MSG    "PortsUp incorrect."
+#define SKERR_RLMT_E005                (SKERR_RLMT_E004 + 1)
+#define SKERR_RLMT_E005_MSG    \
+ "Net seems to be segmented (different root bridges are reported on the ports)."
+#define SKERR_RLMT_E006                (SKERR_RLMT_E005 + 1)
+#define SKERR_RLMT_E006_MSG    "Duplicate MAC Address detected."
+#define SKERR_RLMT_E007                (SKERR_RLMT_E006 + 1)
+#define SKERR_RLMT_E007_MSG    "LinksUp incorrect."
+#define SKERR_RLMT_E008                (SKERR_RLMT_E007 + 1)
+#define SKERR_RLMT_E008_MSG    "Port not started but link came up."
+#define SKERR_RLMT_E009                (SKERR_RLMT_E008 + 1)
+#define SKERR_RLMT_E009_MSG    "Corrected illegal setting of Preferred Port."
+#define SKERR_RLMT_E010                (SKERR_RLMT_E009 + 1)
+#define SKERR_RLMT_E010_MSG    "Ignored illegal Preferred Port."
+
+/* LLC field values. */
+#define LLC_COMMAND_RESPONSE_BIT               1
+#define LLC_TEST_COMMAND                               0xE3
+#define LLC_UI                                                 0x03
+
+/* RLMT Packet fields. */
+#define        SK_RLMT_DSAP                                    0
+#define        SK_RLMT_SSAP                                    0
+#define SK_RLMT_CTRL                                   (LLC_TEST_COMMAND)
+#define SK_RLMT_INDICATOR0                             0x53    /* S */
+#define SK_RLMT_INDICATOR1                             0x4B    /* K */
+#define SK_RLMT_INDICATOR2                             0x2D    /* - */
+#define SK_RLMT_INDICATOR3                             0x52    /* R */
+#define SK_RLMT_INDICATOR4                             0x4C    /* L */
+#define SK_RLMT_INDICATOR5                             0x4D    /* M */
+#define SK_RLMT_INDICATOR6                             0x54    /* T */
+#define SK_RLMT_PACKET_VERSION                 0
+
+/* RLMT SPT Flag values. */
+#define        SK_RLMT_SPT_FLAG_CHANGE                 0x01
+#define        SK_RLMT_SPT_FLAG_CHANGE_ACK             0x80
+
+/* RLMT SPT Packet fields. */
+#define        SK_RLMT_SPT_DSAP                                0x42
+#define        SK_RLMT_SPT_SSAP                                0x42
+#define SK_RLMT_SPT_CTRL                               (LLC_UI)
+#define        SK_RLMT_SPT_PROTOCOL_ID0                0x00
+#define        SK_RLMT_SPT_PROTOCOL_ID1                0x00
+#define        SK_RLMT_SPT_PROTOCOL_VERSION_ID 0x00
+#define        SK_RLMT_SPT_BPDU_TYPE                   0x00
+#define        SK_RLMT_SPT_FLAGS                               0x00    /* ?? */
+#define        SK_RLMT_SPT_ROOT_ID0                    0xFF    /* Lowest possible priority. */
+#define        SK_RLMT_SPT_ROOT_ID1                    0xFF    /* Lowest possible priority. */
+
+/* Remaining 6 bytes will be the current port address. */
+#define        SK_RLMT_SPT_ROOT_PATH_COST0             0x00
+#define        SK_RLMT_SPT_ROOT_PATH_COST1             0x00
+#define        SK_RLMT_SPT_ROOT_PATH_COST2             0x00
+#define        SK_RLMT_SPT_ROOT_PATH_COST3             0x00
+#define        SK_RLMT_SPT_BRIDGE_ID0                  0xFF    /* Lowest possible priority. */
+#define        SK_RLMT_SPT_BRIDGE_ID1                  0xFF    /* Lowest possible priority. */
+
+/* Remaining 6 bytes will be the current port address. */
+#define        SK_RLMT_SPT_PORT_ID0                    0xFF    /* Lowest possible priority. */
+#define        SK_RLMT_SPT_PORT_ID1                    0xFF    /* Lowest possible priority. */
+#define        SK_RLMT_SPT_MSG_AGE0                    0x00
+#define        SK_RLMT_SPT_MSG_AGE1                    0x00
+#define        SK_RLMT_SPT_MAX_AGE0                    0x00
+#define        SK_RLMT_SPT_MAX_AGE1                    0xFF
+#define        SK_RLMT_SPT_HELLO_TIME0                 0x00
+#define        SK_RLMT_SPT_HELLO_TIME1                 0xFF
+#define        SK_RLMT_SPT_FWD_DELAY0                  0x00
+#define        SK_RLMT_SPT_FWD_DELAY1                  0x40
+
+/* Size defines. */
+#define SK_RLMT_MIN_PACKET_SIZE                        34
+#define SK_RLMT_MAX_PACKET_SIZE                        (SK_RLMT_MAX_TX_BUF_SIZE)
+#define SK_PACKET_DATA_LEN                             (SK_RLMT_MAX_PACKET_SIZE - \
+                                                                               SK_RLMT_MIN_PACKET_SIZE)
+
+/* ----- RLMT packet types ----- */
+#define SK_PACKET_ANNOUNCE                             1       /* Port announcement. */
+#define SK_PACKET_ALIVE                                        2       /* Alive packet to port. */
+#define SK_PACKET_ADDR_CHANGED                 3       /* Port address changed. */
+#define SK_PACKET_CHECK_TX                             4       /* Check your tx line. */
+
+#ifdef SK_LITTLE_ENDIAN
+#define SK_U16_TO_NETWORK_ORDER(Val,Addr) { \
+       SK_U8   *_Addr = (SK_U8*)(Addr); \
+       SK_U16  _Val = (SK_U16)(Val); \
+       *_Addr++ = (SK_U8)(_Val >> 8); \
+       *_Addr = (SK_U8)(_Val & 0xFF); \
+}
+#endif /* SK_LITTLE_ENDIAN */
+
+#ifdef SK_BIG_ENDIAN
+#define SK_U16_TO_NETWORK_ORDER(Val,Addr) (*(SK_U16*)(Addr) = (SK_U16)(Val))
+#endif /* SK_BIG_ENDIAN */
+
+#define AUTONEG_FAILED SK_FALSE
+#define AUTONEG_SUCCESS        SK_TRUE
+
+
+/* typedefs *******************************************************************/
+
+/* RLMT packet.  Length: SK_RLMT_MAX_PACKET_SIZE (60) bytes. */
+typedef struct s_RlmtPacket {
+       SK_U8   DstAddr[SK_MAC_ADDR_LEN];
+       SK_U8   SrcAddr[SK_MAC_ADDR_LEN];
+       SK_U8   TypeLen[2];
+       SK_U8   DSap;
+       SK_U8   SSap;
+       SK_U8   Ctrl;
+       SK_U8   Indicator[7];
+       SK_U8   RlmtPacketType[2];
+       SK_U8   Align1[2];
+       SK_U8   Random[4];                              /* Random value of requesting(!) station. */
+       SK_U8   RlmtPacketVersion[2];   /* RLMT Packet version. */
+       SK_U8   Data[SK_PACKET_DATA_LEN];
+} SK_RLMT_PACKET;
+
+typedef struct s_SpTreeRlmtPacket {
+       SK_U8   DstAddr[SK_MAC_ADDR_LEN];
+       SK_U8   SrcAddr[SK_MAC_ADDR_LEN];
+       SK_U8   TypeLen[2];
+       SK_U8   DSap;
+       SK_U8   SSap;
+       SK_U8   Ctrl;
+       SK_U8   ProtocolId[2];
+       SK_U8   ProtocolVersionId;
+       SK_U8   BpduType;
+       SK_U8   Flags;
+       SK_U8   RootId[8];
+       SK_U8   RootPathCost[4];
+       SK_U8   BridgeId[8];
+       SK_U8   PortId[2];
+       SK_U8   MessageAge[2];
+       SK_U8   MaxAge[2];
+       SK_U8   HelloTime[2];
+       SK_U8   ForwardDelay[2];
+} SK_SPTREE_PACKET;
+
+/* global variables ***********************************************************/
+
+SK_MAC_ADDR    SkRlmtMcAddr =  {{0x01,  0x00,  0x5A,  0x52,  0x4C,  0x4D}};
+SK_MAC_ADDR    BridgeMcAddr =  {{0x01,  0x80,  0xC2,  0x00,  0x00,  0x00}};
+
+/* local variables ************************************************************/
+
+/* None. */
+
+/* functions ******************************************************************/
+
+RLMT_STATIC void       SkRlmtCheckSwitch(
+       SK_AC   *pAC,
+       SK_IOC  IoC,
+       SK_U32  NetIdx);
+RLMT_STATIC void       SkRlmtCheckSeg(
+       SK_AC   *pAC,
+       SK_IOC  IoC,
+       SK_U32  NetIdx);
+RLMT_STATIC void       SkRlmtEvtSetNets(
+       SK_AC           *pAC,
+       SK_IOC          IoC,
+       SK_EVPARA       Para);
+
+/******************************************************************************
+ *
+ *     SkRlmtInit - initialize data, set state to init
+ *
+ * Description:
+ *
+ *     SK_INIT_DATA
+ *     ============
+ *
+ *     This routine initializes all RLMT-related variables to a known state.
+ *     The initial state is SK_RLMT_RS_INIT.
+ *     All ports are initialized to SK_RLMT_PS_INIT.
+ *
+ *
+ *     SK_INIT_IO
+ *     ==========
+ *
+ *     Nothing.
+ *
+ *
+ *     SK_INIT_RUN
+ *     ===========
+ *
+ *     Determine the adapter's random value.
+ *     Set the hw registers, the "logical MAC address", the
+ *     RLMT multicast address, and eventually the BPDU multicast address.
+ *
+ * Context:
+ *     init, pageable
+ *
+ * Returns:
+ *     Nothing.
+ */
+void   SkRlmtInit(
+SK_AC  *pAC,   /* Adapter Context */
+SK_IOC IoC,    /* I/O Context */
+int            Level)  /* Initialization Level */
+{
+       SK_U32          i, j;
+       SK_U64          Random;
+       SK_EVPARA       Para;
+    SK_MAC_ADDR                VirtualMacAddress;
+    SK_MAC_ADDR                PhysicalAMacAddress;
+    SK_BOOL            VirtualMacAddressSet;
+    SK_BOOL            PhysicalAMacAddressSet;
+
+       SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_INIT,
+               ("RLMT Init level %d.\n", Level))
+
+       switch (Level) {
+       case SK_INIT_DATA:      /* Initialize data structures. */
+               SK_MEMSET((char *)&pAC->Rlmt, 0, sizeof(SK_RLMT));
+
+               for (i = 0; i < SK_MAX_MACS; i++) {
+                       pAC->Rlmt.Port[i].PortState = SK_RLMT_PS_INIT;
+                       pAC->Rlmt.Port[i].LinkDown = SK_TRUE;
+                       pAC->Rlmt.Port[i].PortDown = SK_TRUE;
+                       pAC->Rlmt.Port[i].PortStarted = SK_FALSE;
+                       pAC->Rlmt.Port[i].PortNoRx = SK_FALSE;
+                       pAC->Rlmt.Port[i].RootIdSet = SK_FALSE;
+                       pAC->Rlmt.Port[i].PortNumber = i;
+                       pAC->Rlmt.Port[i].Net = &pAC->Rlmt.Net[0];
+                       pAC->Rlmt.Port[i].AddrPort = &pAC->Addr.Port[i];
+               }
+
+               pAC->Rlmt.NumNets = 1;
+               for (i = 0; i < SK_MAX_NETS; i++) {
+                       pAC->Rlmt.Net[i].RlmtState = SK_RLMT_RS_INIT;
+                       pAC->Rlmt.Net[i].RootIdSet = SK_FALSE;
+                       pAC->Rlmt.Net[i].PrefPort = SK_RLMT_DEF_PREF_PORT;
+                       pAC->Rlmt.Net[i].Preference = 0xFFFFFFFF;         /* Automatic. */
+                       /* Just assuming. */
+                       pAC->Rlmt.Net[i].ActivePort = pAC->Rlmt.Net[i].PrefPort;
+                       pAC->Rlmt.Net[i].RlmtMode = SK_RLMT_DEF_MODE;
+                       pAC->Rlmt.Net[i].TimeoutValue = SK_RLMT_DEF_TO_VAL;
+                       pAC->Rlmt.Net[i].NetNumber = i;
+               }
+
+               pAC->Rlmt.Net[0].Port[0] = &pAC->Rlmt.Port[0];
+               pAC->Rlmt.Net[0].Port[1] = &pAC->Rlmt.Port[1];
+#if SK_MAX_NETS > 1
+               pAC->Rlmt.Net[1].Port[0] = &pAC->Rlmt.Port[1];
+#endif /* SK_MAX_NETS > 1 */
+               break;
+
+       case SK_INIT_IO:        /* GIMacsFound first available here. */
+               SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_INIT,
+                       ("RLMT: %d MACs were detected.\n", pAC->GIni.GIMacsFound))
+
+               pAC->Rlmt.Net[0].NumPorts = pAC->GIni.GIMacsFound;
+
+               /* Initialize HW registers? */
+               if (pAC->GIni.GIMacsFound == 1) {
+                       Para.Para32[0] = SK_RLMT_MODE_CLS;
+                       Para.Para32[1] = 0;
+                       (void)SkRlmtEvent(pAC, IoC, SK_RLMT_MODE_CHANGE, Para);
+               }
+               break;
+
+       case SK_INIT_RUN:
+               /* Ensure RLMT is set to one net. */
+               if (pAC->Rlmt.NumNets > 1) {
+                       Para.Para32[0] = 1;
+                       Para.Para32[1] = -1;
+                       SkRlmtEvtSetNets(pAC, IoC, Para);
+               }
+
+               for (i = 0; i < (SK_U32)pAC->GIni.GIMacsFound; i++) {
+                       Random = SkOsGetTime(pAC);
+                       *(SK_U32*)&pAC->Rlmt.Port[i].Random = *(SK_U32*)&Random;
+
+                       for (j = 0; j < 4; j++) {
+                               pAC->Rlmt.Port[i].Random[j] ^= pAC->Rlmt.Port[i].AddrPort->
+                                       CurrentMacAddress.a[SK_MAC_ADDR_LEN - 1 - j];
+                       }
+
+                       (void)SkAddrMcClear(pAC, IoC, i, SK_ADDR_PERMANENT | SK_MC_SW_ONLY);
+                       
+                       /* Add RLMT MC address. */
+                       (void)SkAddrMcAdd(pAC, IoC, i, &SkRlmtMcAddr, SK_ADDR_PERMANENT);
+
+                       if (pAC->Rlmt.Net[0].RlmtMode & SK_RLMT_CHECK_SEG) {
+                               /* Add BPDU MC address. */
+                               (void)SkAddrMcAdd(pAC, IoC, i, &BridgeMcAddr, SK_ADDR_PERMANENT);
+                       }
+
+                       (void)SkAddrMcUpdate(pAC, IoC, i);
+               }
+
+       VirtualMacAddressSet = SK_FALSE;
+               /* Read virtual MAC address from Control Register File. */
+               for (j = 0; j < SK_MAC_ADDR_LEN; j++) {
+                       
+            SK_IN8(IoC, B2_MAC_1 + j, &VirtualMacAddress.a[j]);
+            VirtualMacAddressSet |= VirtualMacAddress.a[j];
+               }
+       
+        PhysicalAMacAddressSet = SK_FALSE;
+               /* Read physical MAC address for MAC A from Control Register File. */
+               for (j = 0; j < SK_MAC_ADDR_LEN; j++) {
+                       
+            SK_IN8(IoC, B2_MAC_2 + j, &PhysicalAMacAddress.a[j]);
+            PhysicalAMacAddressSet |= PhysicalAMacAddress.a[j];
+               }
+
+        /* check if the two mac addresses contain reasonable values */
+        if (!VirtualMacAddressSet || !PhysicalAMacAddressSet) {
+
+            pAC->Rlmt.RlmtOff = SK_TRUE;
+        }
+
+        /* if the two mac addresses are equal switch off the RLMT_PRE_LOOKAHEAD
+           and the RLMT_LOOKAHEAD macros */
+        else if (SK_ADDR_EQUAL(PhysicalAMacAddress.a, VirtualMacAddress.a)) {
+
+            pAC->Rlmt.RlmtOff = SK_TRUE;
+        }
+               else {
+                       pAC->Rlmt.RlmtOff = SK_FALSE;
+               }
+               break;
+
+       default:        /* error */
+               break;
+       }
+       return;
+}      /* SkRlmtInit */
+
+
+/******************************************************************************
+ *
+ *     SkRlmtBuildCheckChain - build the check chain
+ *
+ * Description:
+ *     This routine builds the local check chain:
+ *     - Each port that is up checks the next port.
+ *     - The last port that is up checks the first port that is up.
+ *
+ * Notes:
+ *     - Currently only local ports are considered when building the chain.
+ *     - Currently the SuspectState is just reset;
+ *       it would be better to save it ...
+ *
+ * Context:
+ *     runtime, pageable?
+ *
+ * Returns:
+ *     Nothing
+ */
+RLMT_STATIC void       SkRlmtBuildCheckChain(
+SK_AC  *pAC,   /* Adapter Context */
+SK_U32 NetIdx) /* Net Number */
+{
+       SK_U32                  i;
+       SK_U32                  NumMacsUp;
+       SK_RLMT_PORT *  FirstMacUp;
+       SK_RLMT_PORT *  PrevMacUp;
+
+       FirstMacUp      = NULL;
+       PrevMacUp       = NULL;
+       
+       if (!(pAC->Rlmt.Net[NetIdx].RlmtMode & SK_RLMT_CHECK_LOC_LINK)) {
+               for (i = 0; i < pAC->Rlmt.Net[i].NumPorts; i++) {
+                       pAC->Rlmt.Net[NetIdx].Port[i]->PortsChecked = 0;
+               }
+               return; /* Done. */
+       }
+                       
+       SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+               ("SkRlmtBuildCheckChain.\n"))
+
+       NumMacsUp = 0;
+
+       for (i = 0; i < pAC->Rlmt.Net[NetIdx].NumPorts; i++) {
+               pAC->Rlmt.Net[NetIdx].Port[i]->PortsChecked = 0;
+               pAC->Rlmt.Net[NetIdx].Port[i]->PortsSuspect = 0;
+               pAC->Rlmt.Net[NetIdx].Port[i]->CheckingState &=
+                       ~(SK_RLMT_PCS_RX | SK_RLMT_PCS_TX);
+
+               /*
+                * If more than two links are detected we should consider
+                * checking at least two other ports:
+                * 1. the next port that is not LinkDown and
+                * 2. the next port that is not PortDown.
+                */
+               if (!pAC->Rlmt.Net[NetIdx].Port[i]->LinkDown) {
+                       if (NumMacsUp == 0) {
+                               FirstMacUp = pAC->Rlmt.Net[NetIdx].Port[i];
+                       }
+                       else {
+                               PrevMacUp->PortCheck[
+                                       pAC->Rlmt.Net[NetIdx].Port[i]->PortsChecked].CheckAddr =
+                                       pAC->Rlmt.Net[NetIdx].Port[i]->AddrPort->CurrentMacAddress;
+                               PrevMacUp->PortCheck[
+                                       PrevMacUp->PortsChecked].SuspectTx = SK_FALSE;
+                               PrevMacUp->PortsChecked++;
+                       }
+                       PrevMacUp = pAC->Rlmt.Net[NetIdx].Port[i];
+                       NumMacsUp++;
+               }
+       }
+
+       if (NumMacsUp > 1) {
+               PrevMacUp->PortCheck[PrevMacUp->PortsChecked].CheckAddr =
+                       FirstMacUp->AddrPort->CurrentMacAddress;
+               PrevMacUp->PortCheck[PrevMacUp->PortsChecked].SuspectTx =
+                       SK_FALSE;
+               PrevMacUp->PortsChecked++;
+       }
+
+#ifdef DEBUG
+       for (i = 0; i < pAC->Rlmt.Net[NetIdx].NumPorts; i++) {
+               SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+                       ("Port %d checks %d other ports: %2X.\n", i,
+                               pAC->Rlmt.Net[NetIdx].Port[i]->PortsChecked,
+                               pAC->Rlmt.Net[NetIdx].Port[i]->PortCheck[0].CheckAddr.a[5]))
+       }
+#endif /* DEBUG */
+
+       return;
+}      /* SkRlmtBuildCheckChain */
+
+
+/******************************************************************************
+ *
+ *     SkRlmtBuildPacket - build an RLMT packet
+ *
+ * Description:
+ *     This routine sets up an RLMT packet.
+ *
+ * Context:
+ *     runtime, pageable?
+ *
+ * Returns:
+ *     NULL or pointer to RLMT mbuf
+ */
+RLMT_STATIC SK_MBUF    *SkRlmtBuildPacket(
+SK_AC          *pAC,           /* Adapter Context */
+SK_IOC         IoC,            /* I/O Context */
+SK_U32         PortNumber,     /* Sending port */
+SK_U16         PacketType,     /* RLMT packet type */
+SK_MAC_ADDR    *SrcAddr,       /* Source address */
+SK_MAC_ADDR    *DestAddr)      /* Destination address */
+{
+       int             i;
+       SK_U16          Length;
+       SK_MBUF         *pMb;
+       SK_RLMT_PACKET  *pPacket;
+
+#ifdef DEBUG
+       SK_U8   CheckSrc  = 0;
+       SK_U8   CheckDest = 0;
+       
+       for (i = 0; i < SK_MAC_ADDR_LEN; ++i) {
+               CheckSrc  |= SrcAddr->a[i];
+               CheckDest |= DestAddr->a[i];
+       }
+
+       if ((CheckSrc == 0) || (CheckDest == 0)) {
+               SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_ERR,
+                       ("SkRlmtBuildPacket: Invalid %s%saddr.\n",
+                        (CheckSrc == 0 ? "Src" : ""), (CheckDest == 0 ? "Dest" : "")))
+       }
+#endif
+
+       if ((pMb = SkDrvAllocRlmtMbuf(pAC, IoC, SK_RLMT_MAX_PACKET_SIZE)) != NULL) {
+               pPacket = (SK_RLMT_PACKET*)pMb->pData;
+               for (i = 0; i < SK_MAC_ADDR_LEN; i++) {
+                       pPacket->DstAddr[i] = DestAddr->a[i];
+                       pPacket->SrcAddr[i] = SrcAddr->a[i];
+               }
+               pPacket->DSap = SK_RLMT_DSAP;
+               pPacket->SSap = SK_RLMT_SSAP;
+               pPacket->Ctrl = SK_RLMT_CTRL;
+               pPacket->Indicator[0] = SK_RLMT_INDICATOR0;
+               pPacket->Indicator[1] = SK_RLMT_INDICATOR1;
+               pPacket->Indicator[2] = SK_RLMT_INDICATOR2;
+               pPacket->Indicator[3] = SK_RLMT_INDICATOR3;
+               pPacket->Indicator[4] = SK_RLMT_INDICATOR4;
+               pPacket->Indicator[5] = SK_RLMT_INDICATOR5;
+               pPacket->Indicator[6] = SK_RLMT_INDICATOR6;
+
+               SK_U16_TO_NETWORK_ORDER(PacketType, &pPacket->RlmtPacketType[0]);
+
+               for (i = 0; i < 4; i++) {
+                       pPacket->Random[i] = pAC->Rlmt.Port[PortNumber].Random[i];
+               }
+               
+               SK_U16_TO_NETWORK_ORDER(
+                       SK_RLMT_PACKET_VERSION, &pPacket->RlmtPacketVersion[0]);
+
+               for (i = 0; i < SK_PACKET_DATA_LEN; i++) {
+                       pPacket->Data[i] = 0x00;
+               }
+
+               Length = SK_RLMT_MAX_PACKET_SIZE;       /* Or smaller. */
+               pMb->Length = Length;
+               pMb->PortIdx = PortNumber;
+               Length -= 14;
+               SK_U16_TO_NETWORK_ORDER(Length, &pPacket->TypeLen[0]);
+
+               if (PacketType == SK_PACKET_ALIVE) {
+                       pAC->Rlmt.Port[PortNumber].TxHelloCts++;
+               }
+       }
+
+       return (pMb);
+}      /* SkRlmtBuildPacket */
+
+
+/******************************************************************************
+ *
+ *     SkRlmtBuildSpanningTreePacket - build spanning tree check packet
+ *
+ * Description:
+ *     This routine sets up a BPDU packet for spanning tree check.
+ *
+ * Context:
+ *     runtime, pageable?
+ *
+ * Returns:
+ *     NULL or pointer to RLMT mbuf
+ */
+RLMT_STATIC SK_MBUF    *SkRlmtBuildSpanningTreePacket(
+SK_AC  *pAC,           /* Adapter Context */
+SK_IOC IoC,            /* I/O Context */
+SK_U32 PortNumber)     /* Sending port */
+{
+       unsigned                        i;
+       SK_U16                          Length;
+       SK_MBUF                         *pMb;
+       SK_SPTREE_PACKET        *pSPacket;
+
+       if ((pMb = SkDrvAllocRlmtMbuf(pAC, IoC, SK_RLMT_MAX_PACKET_SIZE)) !=
+               NULL) {
+               pSPacket = (SK_SPTREE_PACKET*)pMb->pData;
+               for (i = 0; i < SK_MAC_ADDR_LEN; i++) {
+                       pSPacket->DstAddr[i] = BridgeMcAddr.a[i];
+                       pSPacket->SrcAddr[i] =
+                               pAC->Addr.Port[PortNumber].CurrentMacAddress.a[i];
+               }
+               pSPacket->DSap = SK_RLMT_SPT_DSAP;
+               pSPacket->SSap = SK_RLMT_SPT_SSAP;
+               pSPacket->Ctrl = SK_RLMT_SPT_CTRL;
+
+               pSPacket->ProtocolId[0] = SK_RLMT_SPT_PROTOCOL_ID0;
+               pSPacket->ProtocolId[1] = SK_RLMT_SPT_PROTOCOL_ID1;
+               pSPacket->ProtocolVersionId = SK_RLMT_SPT_PROTOCOL_VERSION_ID;
+               pSPacket->BpduType = SK_RLMT_SPT_BPDU_TYPE;
+               pSPacket->Flags = SK_RLMT_SPT_FLAGS;
+               pSPacket->RootId[0] = SK_RLMT_SPT_ROOT_ID0;
+               pSPacket->RootId[1] = SK_RLMT_SPT_ROOT_ID1;
+               pSPacket->RootPathCost[0] = SK_RLMT_SPT_ROOT_PATH_COST0;
+               pSPacket->RootPathCost[1] = SK_RLMT_SPT_ROOT_PATH_COST1;
+               pSPacket->RootPathCost[2] = SK_RLMT_SPT_ROOT_PATH_COST2;
+               pSPacket->RootPathCost[3] = SK_RLMT_SPT_ROOT_PATH_COST3;
+               pSPacket->BridgeId[0] = SK_RLMT_SPT_BRIDGE_ID0;
+               pSPacket->BridgeId[1] = SK_RLMT_SPT_BRIDGE_ID1;
+
+               /*
+                * Use logical MAC address as bridge ID and filter these packets
+                * on receive.
+                */
+               for (i = 0; i < SK_MAC_ADDR_LEN; i++) {
+                       pSPacket->BridgeId[i + 2] = pSPacket->RootId[i + 2] =
+                               pAC->Addr.Net[pAC->Rlmt.Port[PortNumber].Net->NetNumber].
+                                       CurrentMacAddress.a[i];
+               }
+               pSPacket->PortId[0] = SK_RLMT_SPT_PORT_ID0;
+               pSPacket->PortId[1] = SK_RLMT_SPT_PORT_ID1;
+               pSPacket->MessageAge[0] = SK_RLMT_SPT_MSG_AGE0;
+               pSPacket->MessageAge[1] = SK_RLMT_SPT_MSG_AGE1;
+               pSPacket->MaxAge[0] = SK_RLMT_SPT_MAX_AGE0;
+               pSPacket->MaxAge[1] = SK_RLMT_SPT_MAX_AGE1;
+               pSPacket->HelloTime[0] = SK_RLMT_SPT_HELLO_TIME0;
+               pSPacket->HelloTime[1] = SK_RLMT_SPT_HELLO_TIME1;
+               pSPacket->ForwardDelay[0] = SK_RLMT_SPT_FWD_DELAY0;
+               pSPacket->ForwardDelay[1] = SK_RLMT_SPT_FWD_DELAY1;
+
+               Length = SK_RLMT_MAX_PACKET_SIZE;       /* Or smaller. */
+               pMb->Length = Length;
+               pMb->PortIdx = PortNumber;
+               Length -= 14;
+               SK_U16_TO_NETWORK_ORDER(Length, &pSPacket->TypeLen[0]);
+
+               pAC->Rlmt.Port[PortNumber].TxSpHelloReqCts++;
+       }
+
+       return (pMb);
+}      /* SkRlmtBuildSpanningTreePacket */
+
+
+/******************************************************************************
+ *
+ *     SkRlmtSend - build and send check packets
+ *
+ * Description:
+ *     Depending on the RLMT state and the checking state, several packets
+ *     are sent through the indicated port.
+ *
+ * Context:
+ *     runtime, pageable?
+ *
+ * Returns:
+ *     Nothing.
+ */
+RLMT_STATIC void       SkRlmtSend(
+SK_AC  *pAC,           /* Adapter Context */
+SK_IOC IoC,            /* I/O Context */
+SK_U32 PortNumber)     /* Sending port */
+{
+       unsigned        j;
+       SK_EVPARA       Para;
+       SK_RLMT_PORT    *pRPort;
+
+       pRPort = &pAC->Rlmt.Port[PortNumber];
+       if (pAC->Rlmt.Port[PortNumber].Net->RlmtMode & SK_RLMT_CHECK_LOC_LINK) {
+               if (pRPort->CheckingState & (SK_RLMT_PCS_TX | SK_RLMT_PCS_RX)) {
+                       /* Port is suspicious. Send the RLMT packet to the RLMT mc addr. */
+                       if ((Para.pParaPtr = SkRlmtBuildPacket(pAC, IoC, PortNumber,
+                               SK_PACKET_ALIVE, &pAC->Addr.Port[PortNumber].CurrentMacAddress,
+                               &SkRlmtMcAddr)) != NULL) {
+                               SkEventQueue(pAC, SKGE_DRV, SK_DRV_RLMT_SEND, Para);
+                       }
+               }
+               else {
+                       /*
+                        * Send a directed RLMT packet to all ports that are
+                        * checked by the indicated port.
+                        */
+                       for (j = 0; j < pRPort->PortsChecked; j++) {
+                               if ((Para.pParaPtr = SkRlmtBuildPacket(pAC, IoC, PortNumber,
+                                       SK_PACKET_ALIVE, &pAC->Addr.Port[PortNumber].CurrentMacAddress,
+                                       &pRPort->PortCheck[j].CheckAddr)) != NULL) {
+                                       SkEventQueue(pAC, SKGE_DRV, SK_DRV_RLMT_SEND, Para);
+                               }
+                       }
+               }
+       }
+
+       if ((pAC->Rlmt.Port[PortNumber].Net->RlmtMode & SK_RLMT_CHECK_SEG) &&
+               (pAC->Rlmt.Port[PortNumber].Net->CheckingState & SK_RLMT_RCS_SEND_SEG)) {
+               /*
+                * Send a BPDU packet to make a connected switch tell us
+                * the correct root bridge.
+                */
+               if ((Para.pParaPtr =
+                       SkRlmtBuildSpanningTreePacket(pAC, IoC, PortNumber)) != NULL) {
+                       pAC->Rlmt.Port[PortNumber].Net->CheckingState &= ~SK_RLMT_RCS_SEND_SEG;
+                       pRPort->RootIdSet = SK_FALSE;
+
+                       SkEventQueue(pAC, SKGE_DRV, SK_DRV_RLMT_SEND, Para);
+                       SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_TX,
+                               ("SkRlmtSend: BPDU Packet on Port %u.\n", PortNumber))
+               }
+       }
+       return;
+}      /* SkRlmtSend */
+
+
+/******************************************************************************
+ *
+ *     SkRlmtPortReceives - check if port is (going) down and bring it up
+ *
+ * Description:
+ *     This routine checks if a port who received a non-BPDU packet
+ *     needs to go up or needs to be stopped going down.
+ *
+ * Context:
+ *     runtime, pageable?
+ *
+ * Returns:
+ *     Nothing.
+ */
+RLMT_STATIC void       SkRlmtPortReceives(
+SK_AC  *pAC,                   /* Adapter Context */
+SK_IOC IoC,                    /* I/O Context */
+SK_U32 PortNumber)             /* Port to check */
+{
+       SK_RLMT_PORT    *pRPort;
+       SK_EVPARA               Para;
+
+       pRPort = &pAC->Rlmt.Port[PortNumber];
+       pRPort->PortNoRx = SK_FALSE;
+
+       if ((pRPort->PortState == SK_RLMT_PS_DOWN) &&
+               !(pRPort->CheckingState & SK_RLMT_PCS_TX)) {
+               /*
+                * Port is marked down (rx), but received a non-BPDU packet.
+                * Bring it up.
+                */
+               SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_RX,
+                       ("SkRlmtPacketReceive: Received on PortDown.\n"))
+
+               pRPort->PortState = SK_RLMT_PS_GOING_UP;
+               pRPort->GuTimeStamp = SkOsGetTime(pAC);
+               Para.Para32[0] = PortNumber;
+               Para.Para32[1] = (SK_U32)-1;
+               SkTimerStart(pAC, IoC, &pRPort->UpTimer, SK_RLMT_PORTUP_TIM_VAL,
+                       SKGE_RLMT, SK_RLMT_PORTUP_TIM, Para);
+               pRPort->CheckingState &= ~SK_RLMT_PCS_RX;
+               /* pAC->Rlmt.CheckSwitch = SK_TRUE; */
+               SkRlmtCheckSwitch(pAC, IoC, pRPort->Net->NetNumber);
+       }       /* PortDown && !SuspectTx */
+       else if (pRPort->CheckingState & SK_RLMT_PCS_RX) {
+               SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_RX,
+                       ("SkRlmtPacketReceive: Stop bringing port down.\n"))
+               SkTimerStop(pAC, IoC, &pRPort->DownRxTimer);
+               pRPort->CheckingState &= ~SK_RLMT_PCS_RX;
+               /* pAC->Rlmt.CheckSwitch = SK_TRUE; */
+               SkRlmtCheckSwitch(pAC, IoC, pRPort->Net->NetNumber);
+       }       /* PortGoingDown */
+
+       return;
+}      /* SkRlmtPortReceives */
+
+
+/******************************************************************************
+ *
+ *     SkRlmtPacketReceive - receive a packet for closer examination
+ *
+ * Description:
+ *     This routine examines a packet more closely than SK_RLMT_LOOKAHEAD.
+ *
+ * Context:
+ *     runtime, pageable?
+ *
+ * Returns:
+ *     Nothing.
+ */
+RLMT_STATIC void       SkRlmtPacketReceive(
+SK_AC  *pAC,   /* Adapter Context */
+SK_IOC IoC,    /* I/O Context */
+SK_MBUF        *pMb)   /* Received packet */
+{
+#ifdef xDEBUG
+       extern  void DumpData(char *p, int size);
+#endif /* DEBUG */
+       int                                     i;
+       unsigned                        j;
+       SK_U16                          PacketType;
+       SK_U32                          PortNumber;
+       SK_ADDR_PORT            *pAPort;
+       SK_RLMT_PORT            *pRPort;
+       SK_RLMT_PACKET          *pRPacket;
+       SK_SPTREE_PACKET        *pSPacket;
+       SK_EVPARA                       Para;
+
+       PortNumber      = pMb->PortIdx;
+       pAPort = &pAC->Addr.Port[PortNumber];
+       pRPort = &pAC->Rlmt.Port[PortNumber];
+
+       SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_RX,
+               ("SkRlmtPacketReceive: PortNumber == %d.\n", PortNumber))
+
+       pRPacket = (SK_RLMT_PACKET*)pMb->pData;
+       pSPacket = (SK_SPTREE_PACKET*)pRPacket;
+
+#ifdef xDEBUG
+       DumpData((char *)pRPacket, 32);
+#endif /* DEBUG */
+
+       if ((pRPort->PacketsPerTimeSlot - pRPort->BpduPacketsPerTimeSlot) != 0) {
+               SkRlmtPortReceives(pAC, IoC, PortNumber);
+       }
+       
+       /* Check destination address. */
+
+       if (!SK_ADDR_EQUAL(pAPort->CurrentMacAddress.a, pRPacket->DstAddr) &&
+               !SK_ADDR_EQUAL(SkRlmtMcAddr.a, pRPacket->DstAddr) &&
+               !SK_ADDR_EQUAL(BridgeMcAddr.a, pRPacket->DstAddr)) {
+
+               /* Not sent to current MAC or registered MC address => Trash it. */
+               SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_RX,
+                       ("SkRlmtPacketReceive: Not for me.\n"))
+
+               SkDrvFreeRlmtMbuf(pAC, IoC, pMb);
+               return;
+       }
+       else if (SK_ADDR_EQUAL(pAPort->CurrentMacAddress.a, pRPacket->SrcAddr)) {
+
+               /*
+                * Was sent by same port (may happen during port switching
+                * or in case of duplicate MAC addresses).
+                */
+
+               /*
+                * Check for duplicate address here:
+                * If Packet.Random != My.Random => DupAddr.
+                */
+               for (i = 3; i >= 0; i--) {
+                       if (pRPort->Random[i] != pRPacket->Random[i]) {
+                               break;
+                       }
+               }
+
+               /*
+                * CAUTION: Do not check for duplicate MAC address in RLMT Alive Reply
+                * packets (they have the LLC_COMMAND_RESPONSE_BIT set in
+                * pRPacket->SSap).
+                */
+               if (i >= 0 && pRPacket->DSap == SK_RLMT_DSAP &&
+                       pRPacket->Ctrl == SK_RLMT_CTRL &&
+                       pRPacket->SSap == SK_RLMT_SSAP &&
+                       pRPacket->Indicator[0] == SK_RLMT_INDICATOR0 &&
+                       pRPacket->Indicator[1] == SK_RLMT_INDICATOR1 &&
+                       pRPacket->Indicator[2] == SK_RLMT_INDICATOR2 &&
+                       pRPacket->Indicator[3] == SK_RLMT_INDICATOR3 &&
+                       pRPacket->Indicator[4] == SK_RLMT_INDICATOR4 &&
+                       pRPacket->Indicator[5] == SK_RLMT_INDICATOR5 &&
+                       pRPacket->Indicator[6] == SK_RLMT_INDICATOR6) {
+                       SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_RX,
+                               ("SkRlmtPacketReceive: Duplicate MAC Address.\n"))
+
+                       /* Error Log entry. */
+                       SK_ERR_LOG(pAC, SK_ERRCL_COMM, SKERR_RLMT_E006, SKERR_RLMT_E006_MSG);
+               }
+               else {
+                       /* Simply trash it. */
+                       SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_RX,
+                               ("SkRlmtPacketReceive: Sent by me.\n"))
+               }
+
+               SkDrvFreeRlmtMbuf(pAC, IoC, pMb);
+               return;
+       }
+
+       /* Check SuspectTx entries. */
+       if (pRPort->PortsSuspect > 0) {
+               for (j = 0; j < pRPort->PortsChecked; j++) {
+                       if (pRPort->PortCheck[j].SuspectTx &&
+                               SK_ADDR_EQUAL(
+                                       pRPacket->SrcAddr, pRPort->PortCheck[j].CheckAddr.a)) {
+                               pRPort->PortCheck[j].SuspectTx = SK_FALSE;
+                               pRPort->PortsSuspect--;
+                               break;
+                       }
+               }
+       }
+
+       /* Determine type of packet. */
+       if (pRPacket->DSap == SK_RLMT_DSAP &&
+               pRPacket->Ctrl == SK_RLMT_CTRL &&
+               (pRPacket->SSap & ~LLC_COMMAND_RESPONSE_BIT) == SK_RLMT_SSAP &&
+               pRPacket->Indicator[0] == SK_RLMT_INDICATOR0 &&
+               pRPacket->Indicator[1] == SK_RLMT_INDICATOR1 &&
+               pRPacket->Indicator[2] == SK_RLMT_INDICATOR2 &&
+               pRPacket->Indicator[3] == SK_RLMT_INDICATOR3 &&
+               pRPacket->Indicator[4] == SK_RLMT_INDICATOR4 &&
+               pRPacket->Indicator[5] == SK_RLMT_INDICATOR5 &&
+               pRPacket->Indicator[6] == SK_RLMT_INDICATOR6) {
+
+               /* It's an RLMT packet. */
+               PacketType = (SK_U16)((pRPacket->RlmtPacketType[0] << 8) |
+                       pRPacket->RlmtPacketType[1]);
+
+               switch (PacketType) {
+               case SK_PACKET_ANNOUNCE:        /* Not yet used. */
+#if 0
+                       /* Build the check chain. */
+                       SkRlmtBuildCheckChain(pAC);
+#endif /* 0 */
+
+                       SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_RX,
+                               ("SkRlmtPacketReceive: Announce.\n"))
+
+                       SkDrvFreeRlmtMbuf(pAC, IoC, pMb);
+                       break;
+
+               case SK_PACKET_ALIVE:
+                       if (pRPacket->SSap & LLC_COMMAND_RESPONSE_BIT) {
+                               SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_RX,
+                                       ("SkRlmtPacketReceive: Alive Reply.\n"))
+
+                               if (!(pAC->Addr.Port[PortNumber].PromMode & SK_PROM_MODE_LLC) ||
+                                       SK_ADDR_EQUAL(
+                                               pRPacket->DstAddr, pAPort->CurrentMacAddress.a)) {
+                                       /* Obviously we could send something. */
+                                       if (pRPort->CheckingState & SK_RLMT_PCS_TX) {
+                                               pRPort->CheckingState &=  ~SK_RLMT_PCS_TX;
+                                               SkTimerStop(pAC, IoC, &pRPort->DownTxTimer);
+                                       }
+
+                                       if ((pRPort->PortState == SK_RLMT_PS_DOWN) &&
+                                               !(pRPort->CheckingState & SK_RLMT_PCS_RX)) {
+                                               pRPort->PortState = SK_RLMT_PS_GOING_UP;
+                                               pRPort->GuTimeStamp = SkOsGetTime(pAC);
+
+                                               SkTimerStop(pAC, IoC, &pRPort->DownTxTimer);
+
+                                               Para.Para32[0] = PortNumber;
+                                               Para.Para32[1] = (SK_U32)-1;
+                                               SkTimerStart(pAC, IoC, &pRPort->UpTimer,
+                                                       SK_RLMT_PORTUP_TIM_VAL, SKGE_RLMT,
+                                                       SK_RLMT_PORTUP_TIM, Para);
+                                       }
+                               }
+
+                               /* Mark sending port as alive? */
+                               SkDrvFreeRlmtMbuf(pAC, IoC, pMb);
+                       }
+                       else {  /* Alive Request Packet. */
+                               SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_RX,
+                                       ("SkRlmtPacketReceive: Alive Request.\n"))
+
+                               pRPort->RxHelloCts++;
+
+                               /* Answer. */
+                               for (i = 0; i < SK_MAC_ADDR_LEN; i++) {
+                                       pRPacket->DstAddr[i] = pRPacket->SrcAddr[i];
+                                       pRPacket->SrcAddr[i] =
+                                               pAC->Addr.Port[PortNumber].CurrentMacAddress.a[i];
+                               }
+                               pRPacket->SSap |= LLC_COMMAND_RESPONSE_BIT;
+
+                               Para.pParaPtr = pMb;
+                               SkEventQueue(pAC, SKGE_DRV, SK_DRV_RLMT_SEND, Para);
+                       }
+                       break;
+
+               case SK_PACKET_CHECK_TX:
+                       SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_RX,
+                               ("SkRlmtPacketReceive: Check your tx line.\n"))
+
+                       /* A port checking us requests us to check our tx line. */
+                       pRPort->CheckingState |= SK_RLMT_PCS_TX;
+
+                       /* Start PortDownTx timer. */
+                       Para.Para32[0] = PortNumber;
+                       Para.Para32[1] = (SK_U32)-1;
+                       SkTimerStart(pAC, IoC, &pRPort->DownTxTimer,
+                               SK_RLMT_PORTDOWN_TIM_VAL, SKGE_RLMT,
+                               SK_RLMT_PORTDOWN_TX_TIM, Para);
+
+                       SkDrvFreeRlmtMbuf(pAC, IoC, pMb);
+
+                       if ((Para.pParaPtr = SkRlmtBuildPacket(pAC, IoC, PortNumber,
+                               SK_PACKET_ALIVE, &pAC->Addr.Port[PortNumber].CurrentMacAddress,
+                               &SkRlmtMcAddr)) != NULL) {
+                               SkEventQueue(pAC, SKGE_DRV, SK_DRV_RLMT_SEND, Para);
+                       }
+                       break;
+
+               case SK_PACKET_ADDR_CHANGED:
+                       SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_RX,
+                               ("SkRlmtPacketReceive: Address Change.\n"))
+
+                       /* Build the check chain. */
+                       SkRlmtBuildCheckChain(pAC, pRPort->Net->NetNumber);
+                       SkDrvFreeRlmtMbuf(pAC, IoC, pMb);
+                       break;
+
+               default:
+                       SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_RX,
+                               ("SkRlmtPacketReceive: Unknown RLMT packet.\n"))
+
+                       /* RA;:;: ??? */
+                       SkDrvFreeRlmtMbuf(pAC, IoC, pMb);
+               }
+       }
+       else if (pSPacket->DSap == SK_RLMT_SPT_DSAP &&
+               pSPacket->Ctrl == SK_RLMT_SPT_CTRL &&
+               (pSPacket->SSap & ~LLC_COMMAND_RESPONSE_BIT) == SK_RLMT_SPT_SSAP) {
+               SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_RX,
+                       ("SkRlmtPacketReceive: BPDU Packet.\n"))
+
+               /* Spanning Tree packet. */
+               pRPort->RxSpHelloCts++;
+
+               if (!SK_ADDR_EQUAL(&pSPacket->RootId[2], &pAC->Addr.Net[pAC->Rlmt.
+                       Port[PortNumber].Net->NetNumber].CurrentMacAddress.a[0])) {
+                       /*
+                        * Check segmentation if a new root bridge is set and
+                        * the segmentation check is not currently running.
+                        */
+                       if (!SK_ADDR_EQUAL(&pSPacket->RootId[2], &pRPort->Root.Id[2]) &&
+                               (pAC->Rlmt.Port[PortNumber].Net->LinksUp > 1) &&
+                               (pAC->Rlmt.Port[PortNumber].Net->RlmtMode & SK_RLMT_CHECK_SEG)
+                               != 0 && (pAC->Rlmt.Port[PortNumber].Net->CheckingState &
+                               SK_RLMT_RCS_SEG) == 0) {
+                               pAC->Rlmt.Port[PortNumber].Net->CheckingState |=
+                                       SK_RLMT_RCS_START_SEG | SK_RLMT_RCS_SEND_SEG;
+                       }
+
+                       /* Store tree view of this port. */
+                       for (i = 0; i < 8; i++) {
+                               pRPort->Root.Id[i] = pSPacket->RootId[i];
+                       }
+                       pRPort->RootIdSet = SK_TRUE;
+
+                       SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_DUMP,
+                               ("Root ID %d: %02x %02x %02x %02x %02x %02x %02x %02x.\n",
+                                       PortNumber,
+                                       pRPort->Root.Id[0], pRPort->Root.Id[1],
+                                       pRPort->Root.Id[2], pRPort->Root.Id[3],
+                                       pRPort->Root.Id[4], pRPort->Root.Id[5],
+                                       pRPort->Root.Id[6], pRPort->Root.Id[7]))
+               }
+
+               SkDrvFreeRlmtMbuf(pAC, IoC, pMb);
+               if ((pAC->Rlmt.Port[PortNumber].Net->CheckingState &
+                       SK_RLMT_RCS_REPORT_SEG) != 0) {
+                       SkRlmtCheckSeg(pAC, IoC, pAC->Rlmt.Port[PortNumber].Net->NetNumber);
+               }
+       }
+       else {
+               SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_RX,
+                       ("SkRlmtPacketReceive: Unknown Packet Type.\n"))
+
+               /* Unknown packet. */
+               SkDrvFreeRlmtMbuf(pAC, IoC, pMb);
+       }
+       return;
+}      /* SkRlmtPacketReceive */
+
+
+/******************************************************************************
+ *
+ *     SkRlmtCheckPort - check if a port works
+ *
+ * Description:
+ *     This routine checks if a port whose link is up received something
+ *     and if it seems to transmit successfully.
+ *
+ *     # PortState: PsInit, PsLinkDown, PsDown, PsGoingUp, PsUp
+ *     # PortCheckingState (Bitfield): ChkTx, ChkRx, ChkSeg
+ *     # RlmtCheckingState (Bitfield): ChkSeg, StartChkSeg, ReportSeg
+ *
+ *     if (Rx - RxBpdu == 0) { # No rx.
+ *             if (state == PsUp) {
+ *                     PortCheckingState |= ChkRx
+ *             }
+ *             if (ModeCheckSeg && (Timeout ==
+ *                     TO_SHORTEN(RLMT_DEFAULT_TIMEOUT))) {
+ *                     RlmtCheckingState |= ChkSeg)
+ *                     PortCheckingState |= ChkSeg
+ *             }
+ *             NewTimeout = TO_SHORTEN(Timeout)
+ *             if (NewTimeout < RLMT_MIN_TIMEOUT) {
+ *                     NewTimeout = RLMT_MIN_TIMEOUT
+ *                     PortState = PsDown
+ *                     ...
+ *             }
+ *     }
+ *     else {  # something was received
+ *             # Set counter to 0 at LinkDown?
+ *             #   No - rx may be reported after LinkDown ???
+ *             PortCheckingState &= ~ChkRx
+ *             NewTimeout = RLMT_DEFAULT_TIMEOUT
+ *             if (RxAck == 0) {
+ *                     possible reasons:
+ *                     is my tx line bad? --
+ *                             send RLMT multicast and report
+ *                             back internally? (only possible
+ *                             between ports on same adapter)
+ *             }
+ *             if (RxChk == 0) {
+ *                     possible reasons:
+ *                     - tx line of port set to check me
+ *                       maybe bad
+ *                     - no other port/adapter available or set
+ *                       to check me
+ *                     - adapter checking me has a longer
+ *                       timeout
+ *                     ??? anything that can be done here?
+ *             }
+ *     }
+ *
+ * Context:
+ *     runtime, pageable?
+ *
+ * Returns:
+ *     New timeout value.
+ */
+RLMT_STATIC SK_U32     SkRlmtCheckPort(
+SK_AC  *pAC,           /* Adapter Context */
+SK_IOC IoC,            /* I/O Context */
+SK_U32 PortNumber)     /* Port to check */
+{
+       unsigned                i;
+       SK_U32                  NewTimeout;
+       SK_RLMT_PORT    *pRPort;
+       SK_EVPARA               Para;
+
+       pRPort = &pAC->Rlmt.Port[PortNumber];
+
+       if ((pRPort->PacketsPerTimeSlot - pRPort->BpduPacketsPerTimeSlot) == 0) {
+               SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+                       ("SkRlmtCheckPort %d: No (%d) receives in last time slot.\n",
+                               PortNumber, pRPort->PacketsPerTimeSlot))
+
+               /*
+                * Check segmentation if there was no receive at least twice
+                * in a row (PortNoRx is already set) and the segmentation
+                * check is not currently running.
+                */
+
+               if (pRPort->PortNoRx && (pAC->Rlmt.Port[PortNumber].Net->LinksUp > 1) &&
+                       (pAC->Rlmt.Port[PortNumber].Net->RlmtMode & SK_RLMT_CHECK_SEG) &&
+                       !(pAC->Rlmt.Port[PortNumber].Net->CheckingState & SK_RLMT_RCS_SEG)) {
+                       pAC->Rlmt.Port[PortNumber].Net->CheckingState |=
+                               SK_RLMT_RCS_START_SEG | SK_RLMT_RCS_SEND_SEG;
+               }
+
+               SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+                       ("SkRlmtCheckPort: PortsSuspect %d, PcsRx %d.\n",
+                               pRPort->PortsSuspect, pRPort->CheckingState & SK_RLMT_PCS_RX))
+
+               if (pRPort->PortState != SK_RLMT_PS_DOWN) {
+                       NewTimeout = TO_SHORTEN(pAC->Rlmt.Port[PortNumber].Net->TimeoutValue);
+                       if (NewTimeout < SK_RLMT_MIN_TO_VAL) {
+                               NewTimeout = SK_RLMT_MIN_TO_VAL;
+                       }
+
+                       if (!(pRPort->CheckingState & SK_RLMT_PCS_RX)) {
+                               Para.Para32[0] = PortNumber;
+                               pRPort->CheckingState |= SK_RLMT_PCS_RX;
+
+                               /*
+                                * What shall we do if the port checked by this one receives
+                                * our request frames?  What's bad - our rx line or his tx line?
+                                */
+                               Para.Para32[1] = (SK_U32)-1;
+                               SkTimerStart(pAC, IoC, &pRPort->DownRxTimer,
+                                       SK_RLMT_PORTDOWN_TIM_VAL, SKGE_RLMT,
+                                       SK_RLMT_PORTDOWN_RX_TIM, Para);
+
+                               for (i = 0; i < pRPort->PortsChecked; i++) {
+                                       if (pRPort->PortCheck[i].SuspectTx) {
+                                               continue;
+                                       }
+                                       pRPort->PortCheck[i].SuspectTx = SK_TRUE;
+                                       pRPort->PortsSuspect++;
+                                       if ((Para.pParaPtr =
+                                               SkRlmtBuildPacket(pAC, IoC, PortNumber, SK_PACKET_CHECK_TX,
+                                                       &pAC->Addr.Port[PortNumber].CurrentMacAddress,
+                                                       &pRPort->PortCheck[i].CheckAddr)) != NULL) {
+                                               SkEventQueue(pAC, SKGE_DRV, SK_DRV_RLMT_SEND, Para);
+                                       }
+                               }
+                       }
+               }
+               else {  /* PortDown -- or all partners suspect. */
+                       NewTimeout = SK_RLMT_DEF_TO_VAL;
+               }
+               pRPort->PortNoRx = SK_TRUE;
+       }
+       else {  /* A non-BPDU packet was received. */
+               SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+                       ("SkRlmtCheckPort %d: %d (%d) receives in last time slot.\n",
+                               PortNumber,
+                               pRPort->PacketsPerTimeSlot - pRPort->BpduPacketsPerTimeSlot,
+                               pRPort->PacketsPerTimeSlot))
+               
+               SkRlmtPortReceives(pAC, IoC, PortNumber);
+               if (pAC->Rlmt.CheckSwitch) {
+                       SkRlmtCheckSwitch(pAC, IoC, pRPort->Net->NetNumber);
+               }
+
+               NewTimeout = SK_RLMT_DEF_TO_VAL;
+       }
+
+       return (NewTimeout);
+}      /* SkRlmtCheckPort */
+
+
+/******************************************************************************
+ *
+ *     SkRlmtSelectBcRx - select new active port, criteria 1 (CLP)
+ *
+ * Description:
+ *     This routine selects the port that received a broadcast frame
+ *     substantially later than all other ports.
+ *
+ * Context:
+ *     runtime, pageable?
+ *
+ * Returns:
+ *     SK_BOOL
+ */
+RLMT_STATIC SK_BOOL    SkRlmtSelectBcRx(
+SK_AC  *pAC,           /* Adapter Context */
+SK_IOC IoC,            /* I/O Context */
+SK_U32 Active,         /* Active port */
+SK_U32 PrefPort,       /* Preferred port */
+SK_U32 *pSelect)       /* New active port */
+{
+       SK_U64          BcTimeStamp;
+       SK_U32          i;
+       SK_BOOL         PortFound;
+
+       BcTimeStamp = 0;        /* Not totally necessary, but feeling better. */
+       PortFound = SK_FALSE;
+       
+       /* Select port with the latest TimeStamp. */
+       for (i = 0; i < (SK_U32)pAC->GIni.GIMacsFound; i++) {
+
+               SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+                       ("TimeStamp Port %d (Down: %d, NoRx: %d): %08x %08x.\n",
+                               i,
+                               pAC->Rlmt.Port[i].PortDown, pAC->Rlmt.Port[i].PortNoRx,
+                               *((SK_U32*)(&pAC->Rlmt.Port[i].BcTimeStamp) + OFFS_HI32),
+                               *((SK_U32*)(&pAC->Rlmt.Port[i].BcTimeStamp) + OFFS_LO32)))
+
+               if (!pAC->Rlmt.Port[i].PortDown && !pAC->Rlmt.Port[i].PortNoRx) {
+                       if (!PortFound || pAC->Rlmt.Port[i].BcTimeStamp > BcTimeStamp) {
+                               BcTimeStamp = pAC->Rlmt.Port[i].BcTimeStamp;
+                               *pSelect = i;
+                               PortFound = SK_TRUE;
+                       }
+               }
+       }
+
+       if (PortFound) {
+               SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+                       ("Port %d received the last broadcast.\n", *pSelect))
+
+               /* Look if another port's time stamp is similar. */
+               for (i = 0; i < (SK_U32)pAC->GIni.GIMacsFound; i++) {
+                       if (i == *pSelect) {
+                               continue;
+                       }
+                       if (!pAC->Rlmt.Port[i].PortDown && !pAC->Rlmt.Port[i].PortNoRx &&
+                               (pAC->Rlmt.Port[i].BcTimeStamp >
+                                BcTimeStamp - SK_RLMT_BC_DELTA ||
+                               pAC->Rlmt.Port[i].BcTimeStamp +
+                                SK_RLMT_BC_DELTA > BcTimeStamp)) {
+                               PortFound = SK_FALSE;
+                               
+                               SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+                                       ("Port %d received a broadcast at a similar time.\n", i))
+                               break;
+                       }
+               }
+       }
+
+#ifdef DEBUG
+       if (PortFound) {
+               SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+                       ("SK_RLMT_SELECT_BCRX found Port %d receiving the substantially "
+                        "latest broadcast (%u).\n",
+                               *pSelect,
+                               BcTimeStamp - pAC->Rlmt.Port[1 - *pSelect].BcTimeStamp))
+       }
+#endif /* DEBUG */
+
+       return (PortFound);
+}      /* SkRlmtSelectBcRx */
+
+
+/******************************************************************************
+ *
+ *     SkRlmtSelectNotSuspect - select new active port, criteria 2 (CLP)
+ *
+ * Description:
+ *     This routine selects a good port (it is PortUp && !SuspectRx).
+ *
+ * Context:
+ *     runtime, pageable?
+ *
+ * Returns:
+ *     SK_BOOL
+ */
+RLMT_STATIC SK_BOOL    SkRlmtSelectNotSuspect(
+SK_AC  *pAC,           /* Adapter Context */
+SK_IOC IoC,            /* I/O Context */
+SK_U32 Active,         /* Active port */
+SK_U32 PrefPort,       /* Preferred port */
+SK_U32 *pSelect)       /* New active port */
+{
+       SK_U32          i;
+       SK_BOOL         PortFound;
+
+       PortFound = SK_FALSE;
+
+       /* Select first port that is PortUp && !SuspectRx. */
+       for (i = 0; i < (SK_U32)pAC->GIni.GIMacsFound; i++) {
+               if (!pAC->Rlmt.Port[i].PortDown &&
+                       !(pAC->Rlmt.Port[i].CheckingState & SK_RLMT_PCS_RX)) {
+                       *pSelect = i;
+                       if (!pAC->Rlmt.Port[Active].PortDown &&
+                               !(pAC->Rlmt.Port[Active].CheckingState & SK_RLMT_PCS_RX)) {
+                               *pSelect = Active;
+                       }
+                       if (!pAC->Rlmt.Port[PrefPort].PortDown &&
+                               !(pAC->Rlmt.Port[PrefPort].CheckingState & SK_RLMT_PCS_RX)) {
+                               *pSelect = PrefPort;
+                       }
+                       PortFound = SK_TRUE;
+                       SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+                               ("SK_RLMT_SELECT_NOTSUSPECT found Port %d up and not check RX.\n",
+                                       *pSelect))
+                       break;
+               }
+       }
+       return (PortFound);
+}      /* SkRlmtSelectNotSuspect */
+
+
+/******************************************************************************
+ *
+ *     SkRlmtSelectUp - select new active port, criteria 3, 4 (CLP)
+ *
+ * Description:
+ *     This routine selects a port that is up.
+ *
+ * Context:
+ *     runtime, pageable?
+ *
+ * Returns:
+ *     SK_BOOL
+ */
+RLMT_STATIC SK_BOOL    SkRlmtSelectUp(
+SK_AC  *pAC,                   /* Adapter Context */
+SK_IOC IoC,                    /* I/O Context */
+SK_U32 Active,                 /* Active port */
+SK_U32 PrefPort,               /* Preferred port */
+SK_U32 *pSelect,               /* New active port */
+SK_BOOL        AutoNegDone)    /* Successfully auto-negotiated? */
+{
+       SK_U32          i;
+       SK_BOOL         PortFound;
+
+       PortFound = SK_FALSE;
+
+       /* Select first port that is PortUp. */
+       for (i = 0; i < (SK_U32)pAC->GIni.GIMacsFound; i++) {
+               if (pAC->Rlmt.Port[i].PortState == SK_RLMT_PS_UP &&
+                       pAC->GIni.GP[i].PAutoNegFail != AutoNegDone) {
+                       *pSelect = i;
+                       if (pAC->Rlmt.Port[Active].PortState == SK_RLMT_PS_UP &&
+                               pAC->GIni.GP[Active].PAutoNegFail != AutoNegDone) {
+                               *pSelect = Active;
+                       }
+                       if (pAC->Rlmt.Port[PrefPort].PortState == SK_RLMT_PS_UP &&
+                               pAC->GIni.GP[PrefPort].PAutoNegFail != AutoNegDone) {
+                               *pSelect = PrefPort;
+                       }
+                       PortFound = SK_TRUE;
+                       SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+                               ("SK_RLMT_SELECT_UP found Port %d up.\n", *pSelect))
+                       break;
+               }
+       }
+       return (PortFound);
+}      /* SkRlmtSelectUp */
+
+
+/******************************************************************************
+ *
+ *     SkRlmtSelectGoingUp - select new active port, criteria 5, 6 (CLP)
+ *
+ * Description:
+ *     This routine selects the port that is going up for the longest time.
+ *
+ * Context:
+ *     runtime, pageable?
+ *
+ * Returns:
+ *     SK_BOOL
+ */
+RLMT_STATIC SK_BOOL    SkRlmtSelectGoingUp(
+SK_AC  *pAC,                   /* Adapter Context */
+SK_IOC IoC,                    /* I/O Context */
+SK_U32 Active,                 /* Active port */
+SK_U32 PrefPort,               /* Preferred port */
+SK_U32 *pSelect,               /* New active port */
+SK_BOOL        AutoNegDone)    /* Successfully auto-negotiated? */
+{
+       SK_U64          GuTimeStamp;
+       SK_U32          i;
+       SK_BOOL         PortFound;
+
+       GuTimeStamp = 0;
+       PortFound = SK_FALSE;
+
+       /* Select port that is PortGoingUp for the longest time. */
+       for (i = 0; i < (SK_U32)pAC->GIni.GIMacsFound; i++) {
+               if (pAC->Rlmt.Port[i].PortState == SK_RLMT_PS_GOING_UP &&
+                       pAC->GIni.GP[i].PAutoNegFail != AutoNegDone) {
+                       GuTimeStamp = pAC->Rlmt.Port[i].GuTimeStamp;
+                       *pSelect = i;
+                       PortFound = SK_TRUE;
+                       break;
+               }
+       }
+
+       if (!PortFound) {
+               return (SK_FALSE);
+       }
+
+       for (i = *pSelect + 1; i < (SK_U32)pAC->GIni.GIMacsFound; i++) {
+               if (pAC->Rlmt.Port[i].PortState == SK_RLMT_PS_GOING_UP &&
+                       pAC->Rlmt.Port[i].GuTimeStamp < GuTimeStamp &&
+                       pAC->GIni.GP[i].PAutoNegFail != AutoNegDone) {
+                       GuTimeStamp = pAC->Rlmt.Port[i].GuTimeStamp;
+                       *pSelect = i;
+               }
+       }
+
+       SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+               ("SK_RLMT_SELECT_GOINGUP found Port %d going up.\n", *pSelect))
+       return (SK_TRUE);
+}      /* SkRlmtSelectGoingUp */
+
+
+/******************************************************************************
+ *
+ *     SkRlmtSelectDown - select new active port, criteria 7, 8 (CLP)
+ *
+ * Description:
+ *     This routine selects a port that is down.
+ *
+ * Context:
+ *     runtime, pageable?
+ *
+ * Returns:
+ *     SK_BOOL
+ */
+RLMT_STATIC SK_BOOL    SkRlmtSelectDown(
+SK_AC  *pAC,                   /* Adapter Context */
+SK_IOC IoC,                    /* I/O Context */
+SK_U32 Active,                 /* Active port */
+SK_U32 PrefPort,               /* Preferred port */
+SK_U32 *pSelect,               /* New active port */
+SK_BOOL        AutoNegDone)    /* Successfully auto-negotiated? */
+{
+       SK_U32          i;
+       SK_BOOL         PortFound;
+
+       PortFound = SK_FALSE;
+
+       /* Select first port that is PortDown. */
+       for (i = 0; i < (SK_U32)pAC->GIni.GIMacsFound; i++) {
+               if (pAC->Rlmt.Port[i].PortState == SK_RLMT_PS_DOWN &&
+                       pAC->GIni.GP[i].PAutoNegFail != AutoNegDone) {
+                       *pSelect = i;
+                       if (pAC->Rlmt.Port[Active].PortState == SK_RLMT_PS_DOWN &&
+                               pAC->GIni.GP[Active].PAutoNegFail != AutoNegDone) {
+                               *pSelect = Active;
+                       }
+                       if (pAC->Rlmt.Port[PrefPort].PortState == SK_RLMT_PS_DOWN &&
+                               pAC->GIni.GP[PrefPort].PAutoNegFail != AutoNegDone) {
+                               *pSelect = PrefPort;
+                       }
+                       PortFound = SK_TRUE;
+                       SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+                               ("SK_RLMT_SELECT_DOWN found Port %d down.\n", *pSelect))
+                       break;
+               }
+       }
+       return (PortFound);
+}      /* SkRlmtSelectDown */
+
+
+/******************************************************************************
+ *
+ *     SkRlmtCheckSwitch - select new active port and switch to it
+ *
+ * Description:
+ *     This routine decides which port should be the active one and queues
+ *     port switching if necessary.
+ *
+ * Context:
+ *     runtime, pageable?
+ *
+ * Returns:
+ *     Nothing.
+ */
+RLMT_STATIC void       SkRlmtCheckSwitch(
+SK_AC  *pAC,   /* Adapter Context */
+SK_IOC IoC,    /* I/O Context */
+SK_U32 NetIdx) /* Net index */
+{
+       SK_EVPARA       Para;
+       SK_U32          Active;
+       SK_U32          PrefPort;
+       SK_U32          i;
+       SK_BOOL         PortFound;
+
+       Active = pAC->Rlmt.Net[NetIdx].ActivePort;      /* Index of active port. */
+       PrefPort = pAC->Rlmt.Net[NetIdx].PrefPort;      /* Index of preferred port. */
+       PortFound = SK_FALSE;
+       pAC->Rlmt.CheckSwitch = SK_FALSE;
+
+#if 0  /* RW 2001/10/18 - active port becomes always prefered one */
+       if (pAC->Rlmt.Net[NetIdx].Preference == 0xFFFFFFFF) { /* Automatic */
+               /* disable auto-fail back */
+               PrefPort = Active;
+       }
+#endif
+
+       if (pAC->Rlmt.Net[NetIdx].LinksUp == 0) {
+               /* Last link went down - shut down the net. */
+               pAC->Rlmt.Net[NetIdx].RlmtState = SK_RLMT_RS_NET_DOWN;
+               Para.Para32[0] = SK_RLMT_NET_DOWN_TEMP;
+               Para.Para32[1] = NetIdx;
+               SkEventQueue(pAC, SKGE_DRV, SK_DRV_NET_DOWN, Para);
+
+               Para.Para32[0] = pAC->Rlmt.Net[NetIdx].
+                       Port[pAC->Rlmt.Net[NetIdx].ActivePort]->PortNumber;
+               Para.Para32[1] = NetIdx;
+               SkEventQueue(pAC, SKGE_PNMI, SK_PNMI_EVT_RLMT_ACTIVE_DOWN, Para);
+               return;
+       }       /* pAC->Rlmt.LinksUp == 0 */
+       else if (pAC->Rlmt.Net[NetIdx].LinksUp == 1 &&
+               pAC->Rlmt.Net[NetIdx].RlmtState == SK_RLMT_RS_NET_DOWN) {
+               /* First link came up - get the net up. */
+               pAC->Rlmt.Net[NetIdx].RlmtState = SK_RLMT_RS_NET_UP;
+
+               /*
+                * If pAC->Rlmt.ActivePort != Para.Para32[0],
+                * the DRV switches to the port that came up.
+                */
+               for (i = 0; i < pAC->Rlmt.Net[NetIdx].NumPorts; i++) {
+                       if (!pAC->Rlmt.Net[NetIdx].Port[i]->LinkDown) {
+                               if (!pAC->Rlmt.Net[NetIdx].Port[Active]->LinkDown) {
+                                       i = Active;
+                               }
+                               if (!pAC->Rlmt.Net[NetIdx].Port[PrefPort]->LinkDown) {
+                                       i = PrefPort;
+                               }
+                               PortFound = SK_TRUE;
+                               break;
+                       }
+               }
+
+               if (PortFound) {
+                       Para.Para32[0] = pAC->Rlmt.Net[NetIdx].Port[i]->PortNumber;
+                       Para.Para32[1] = NetIdx;
+                       SkEventQueue(pAC, SKGE_PNMI, SK_PNMI_EVT_RLMT_ACTIVE_UP, Para);
+
+                       pAC->Rlmt.Net[NetIdx].ActivePort = i;
+                       Para.Para32[0] = pAC->Rlmt.Net[NetIdx].Port[i]->PortNumber;
+                       Para.Para32[1] = NetIdx;
+                       SkEventQueue(pAC, SKGE_DRV, SK_DRV_NET_UP, Para);
+
+                       if ((pAC->Rlmt.Net[NetIdx].RlmtMode & SK_RLMT_TRANSPARENT) == 0 &&
+                               (Para.pParaPtr = SkRlmtBuildPacket(pAC, IoC,
+                               pAC->Rlmt.Net[NetIdx].Port[i]->PortNumber,
+                               SK_PACKET_ANNOUNCE, &pAC->Addr.Net[NetIdx].
+                               CurrentMacAddress, &SkRlmtMcAddr)) != NULL) {
+                               /*
+                                * Send announce packet to RLMT multicast address to force
+                                * switches to learn the new location of the logical MAC address.
+                                */
+                               SkEventQueue(pAC, SKGE_DRV, SK_DRV_RLMT_SEND, Para);
+                       }
+               }
+               else {
+                       SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_RLMT_E007, SKERR_RLMT_E007_MSG);
+               }
+
+               return;
+       }       /* LinksUp == 1 && RlmtState == SK_RLMT_RS_NET_DOWN */
+       else {  /* Cannot be reached in dual-net mode. */
+               Para.Para32[0] = Active;
+
+               /*
+                * Preselection:
+                *      If RLMT Mode != CheckLinkState
+                *              select port that received a broadcast frame substantially later
+                *              than all other ports
+                *      else select first port that is not SuspectRx
+                *      else select first port that is PortUp
+                *      else select port that is PortGoingUp for the longest time
+                *      else select first port that is PortDown
+                *      else stop.
+                *
+                * For the preselected port:
+                *      If ActivePort is equal in quality, select ActivePort.
+                *
+                *      If PrefPort is equal in quality, select PrefPort.
+                *
+                *      If ActivePort != SelectedPort,
+                *              If old ActivePort is LinkDown,
+                *                      SwitchHard
+                *              else
+                *                      SwitchSoft
+                */
+               /* check of ChgBcPrio flag added */
+               if ((pAC->Rlmt.Net[0].RlmtMode != SK_RLMT_MODE_CLS) &&
+                       (!pAC->Rlmt.Net[0].ChgBcPrio)) {
+                       
+                       if (!PortFound) {
+                               PortFound = SkRlmtSelectBcRx(
+                                       pAC, IoC, Active, PrefPort, &Para.Para32[1]);
+                       }
+
+                       if (!PortFound) {
+                               PortFound = SkRlmtSelectNotSuspect(
+                                       pAC, IoC, Active, PrefPort, &Para.Para32[1]);
+                       }
+               }       /* pAC->Rlmt.RlmtMode != SK_RLMT_MODE_CLS */
+
+               /* with changed priority for last broadcast received */
+               if ((pAC->Rlmt.Net[0].RlmtMode != SK_RLMT_MODE_CLS) &&
+                       (pAC->Rlmt.Net[0].ChgBcPrio)) {
+                       if (!PortFound) {
+                               PortFound = SkRlmtSelectNotSuspect(
+                                       pAC, IoC, Active, PrefPort, &Para.Para32[1]);
+                       }
+
+                       if (!PortFound) {
+                               PortFound = SkRlmtSelectBcRx(
+                                       pAC, IoC, Active, PrefPort, &Para.Para32[1]);
+                       }
+               }       /* pAC->Rlmt.RlmtMode != SK_RLMT_MODE_CLS */
+
+               if (!PortFound) {
+                       PortFound = SkRlmtSelectUp(
+                               pAC, IoC, Active, PrefPort, &Para.Para32[1], AUTONEG_SUCCESS);
+               }
+
+               if (!PortFound) {
+                       PortFound = SkRlmtSelectUp(
+                               pAC, IoC, Active, PrefPort, &Para.Para32[1], AUTONEG_FAILED);
+               }
+
+               if (!PortFound) {
+                       PortFound = SkRlmtSelectGoingUp(
+                               pAC, IoC, Active, PrefPort, &Para.Para32[1], AUTONEG_SUCCESS);
+               }
+
+               if (!PortFound) {
+                       PortFound = SkRlmtSelectGoingUp(
+                               pAC, IoC, Active, PrefPort, &Para.Para32[1], AUTONEG_FAILED);
+               }
+
+               if (pAC->Rlmt.Net[0].RlmtMode != SK_RLMT_MODE_CLS) {
+                       if (!PortFound) {
+                               PortFound = SkRlmtSelectDown(pAC, IoC,
+                                       Active, PrefPort, &Para.Para32[1], AUTONEG_SUCCESS);
+                       }
+
+                       if (!PortFound) {
+                               PortFound = SkRlmtSelectDown(pAC, IoC,
+                                       Active, PrefPort, &Para.Para32[1], AUTONEG_FAILED);
+                       }
+               }       /* pAC->Rlmt.RlmtMode != SK_RLMT_MODE_CLS */
+
+               if (PortFound) {
+
+                       if (Para.Para32[1] != Active) {
+                               SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+                                       ("Active: %d, Para1: %d.\n", Active, Para.Para32[1]))
+                               pAC->Rlmt.Net[NetIdx].ActivePort = Para.Para32[1];
+                               Para.Para32[0] = pAC->Rlmt.Net[NetIdx].
+                                       Port[Para.Para32[0]]->PortNumber;
+                               Para.Para32[1] = pAC->Rlmt.Net[NetIdx].
+                                       Port[Para.Para32[1]]->PortNumber;
+                               SK_HWAC_LINK_LED(pAC, IoC, Para.Para32[1], SK_LED_ACTIVE);
+                               if (pAC->Rlmt.Port[Active].LinkDown) {
+                                       SkEventQueue(pAC, SKGE_DRV, SK_DRV_SWITCH_HARD, Para);
+                               }
+                               else {
+                                       SK_HWAC_LINK_LED(pAC, IoC, Para.Para32[0], SK_LED_STANDBY);
+                                       SkEventQueue(pAC, SKGE_DRV, SK_DRV_SWITCH_SOFT, Para);
+                               }
+                               Para.Para32[1] = NetIdx;
+                               Para.Para32[0] =
+                                       pAC->Rlmt.Net[NetIdx].Port[Para.Para32[0]]->PortNumber;
+                               SkEventQueue(pAC, SKGE_PNMI, SK_PNMI_EVT_RLMT_ACTIVE_DOWN, Para);
+                               Para.Para32[0] = pAC->Rlmt.Net[NetIdx].
+                                       Port[pAC->Rlmt.Net[NetIdx].ActivePort]->PortNumber;
+                               SkEventQueue(pAC, SKGE_PNMI, SK_PNMI_EVT_RLMT_ACTIVE_UP, Para);
+                               if ((pAC->Rlmt.Net[NetIdx].RlmtMode & SK_RLMT_TRANSPARENT) == 0 &&
+                                       (Para.pParaPtr = SkRlmtBuildPacket(pAC, IoC, Para.Para32[0],
+                                       SK_PACKET_ANNOUNCE, &pAC->Addr.Net[NetIdx].CurrentMacAddress,
+                                       &SkRlmtMcAddr)) != NULL) {
+                                       /*
+                                        * Send announce packet to RLMT multicast address to force
+                                        * switches to learn the new location of the logical
+                                        * MAC address.
+                                        */
+                                       SkEventQueue(pAC, SKGE_DRV, SK_DRV_RLMT_SEND, Para);
+                               }       /* (Para.pParaPtr = SkRlmtBuildPacket(...)) != NULL */
+                       }       /* Para.Para32[1] != Active */
+               }       /* PortFound */
+               else {
+                       SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_RLMT_E004, SKERR_RLMT_E004_MSG);
+               }
+       }       /* LinksUp > 1 || LinksUp == 1 && RlmtState != SK_RLMT_RS_NET_DOWN */
+       return;
+}      /* SkRlmtCheckSwitch */
+
+
+/******************************************************************************
+ *
+ *     SkRlmtCheckSeg - Report if segmentation is detected
+ *
+ * Description:
+ *     This routine checks if the ports see different root bridges and reports
+ *     segmentation in such a case.
+ *
+ * Context:
+ *     runtime, pageable?
+ *
+ * Returns:
+ *     Nothing.
+ */
+RLMT_STATIC void       SkRlmtCheckSeg(
+SK_AC  *pAC,   /* Adapter Context */
+SK_IOC IoC,    /* I/O Context */
+SK_U32 NetIdx) /* Net number */
+{
+       SK_EVPARA       Para;
+       SK_RLMT_NET     *pNet;
+       SK_U32          i, j;
+       SK_BOOL         Equal;
+
+       pNet = &pAC->Rlmt.Net[NetIdx];
+       pNet->RootIdSet = SK_FALSE;
+       Equal = SK_TRUE;
+
+       for (i = 0; i < pNet->NumPorts; i++) {
+               if (pNet->Port[i]->LinkDown || !pNet->Port[i]->RootIdSet) {
+                       continue;
+               }
+
+               SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_DUMP,
+                       ("Root ID %d: %02x %02x %02x %02x %02x %02x %02x %02x.\n", i,
+                               pNet->Port[i]->Root.Id[0], pNet->Port[i]->Root.Id[1],
+                               pNet->Port[i]->Root.Id[2], pNet->Port[i]->Root.Id[3],
+                               pNet->Port[i]->Root.Id[4], pNet->Port[i]->Root.Id[5],
+                               pNet->Port[i]->Root.Id[6], pNet->Port[i]->Root.Id[7]))
+
+               if (!pNet->RootIdSet) {
+                       pNet->Root = pNet->Port[i]->Root;
+                       pNet->RootIdSet = SK_TRUE;
+                       continue;
+               }
+
+               for (j = 0; j < 8; j ++) {
+                       Equal &= pNet->Port[i]->Root.Id[j] == pNet->Root.Id[j];
+                       if (!Equal) {
+                               break;
+                       }
+               }
+               
+               if (!Equal) {
+                       SK_ERR_LOG(pAC, SK_ERRCL_COMM, SKERR_RLMT_E005, SKERR_RLMT_E005_MSG);
+                       Para.Para32[0] = NetIdx;
+                       Para.Para32[1] = (SK_U32)-1;
+                       SkEventQueue(pAC, SKGE_PNMI, SK_PNMI_EVT_RLMT_SEGMENTATION, Para);
+
+                       pNet->CheckingState &= ~SK_RLMT_RCS_REPORT_SEG;
+
+                       /* 2000-03-06 RA: New. */
+                       Para.Para32[0] = NetIdx;
+                       Para.Para32[1] = (SK_U32)-1;
+                       SkTimerStart(pAC, IoC, &pNet->SegTimer, SK_RLMT_SEG_TO_VAL,
+                               SKGE_RLMT, SK_RLMT_SEG_TIM, Para);
+                       break;
+               }
+       }       /* for (i = 0; i < pNet->NumPorts; i++) */
+
+       /* 2000-03-06 RA: Moved here. */
+       /* Segmentation check not running anymore. */
+       pNet->CheckingState &= ~SK_RLMT_RCS_SEG;
+
+}      /* SkRlmtCheckSeg */
+
+
+/******************************************************************************
+ *
+ *     SkRlmtPortStart - initialize port variables and start port
+ *
+ * Description:
+ *     This routine initializes a port's variables and issues a PORT_START
+ *     to the HWAC module.  This handles retries if the start fails or the
+ *     link eventually goes down.
+ *
+ * Context:
+ *     runtime, pageable?
+ *
+ * Returns:
+ *     Nothing
+ */
+RLMT_STATIC void       SkRlmtPortStart(
+SK_AC  *pAC,           /* Adapter Context */
+SK_IOC IoC,            /* I/O Context */
+SK_U32 PortNumber)     /* Port number */
+{
+       SK_EVPARA       Para;
+
+       pAC->Rlmt.Port[PortNumber].PortState = SK_RLMT_PS_LINK_DOWN;
+       pAC->Rlmt.Port[PortNumber].PortStarted = SK_TRUE;
+       pAC->Rlmt.Port[PortNumber].LinkDown = SK_TRUE;
+       pAC->Rlmt.Port[PortNumber].PortDown = SK_TRUE;
+       pAC->Rlmt.Port[PortNumber].CheckingState = 0;
+       pAC->Rlmt.Port[PortNumber].RootIdSet = SK_FALSE;
+       Para.Para32[0] = PortNumber;
+       Para.Para32[1] = (SK_U32)-1;
+       SkEventQueue(pAC, SKGE_HWAC, SK_HWEV_PORT_START, Para);
+}      /* SkRlmtPortStart */
+
+
+/******************************************************************************
+ *
+ *     SkRlmtEvtPortStartTim - PORT_START_TIM
+ *
+ * Description:
+ *     This routine handles PORT_START_TIM events.
+ *
+ * Context:
+ *     runtime, pageable?
+ *     may be called after SK_INIT_IO
+ *
+ * Returns:
+ *     Nothing
+ */
+RLMT_STATIC void       SkRlmtEvtPortStartTim(
+SK_AC          *pAC,   /* Adapter Context */
+SK_IOC         IoC,    /* I/O Context */
+SK_EVPARA      Para)   /* SK_U32 PortNumber; SK_U32 -1 */
+{
+       SK_U32                  i;
+
+       SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+               ("SK_RLMT_PORTSTART_TIMEOUT Port %d Event BEGIN.\n", Para.Para32[0]))
+
+               if (Para.Para32[1] != (SK_U32)-1) {
+               SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+                       ("Bad Parameter.\n"))
+               SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+                       ("SK_RLMT_PORTSTART_TIMEOUT Event EMPTY.\n"))
+               return;
+       }
+
+       /*
+        * Used to start non-preferred ports if the preferred one
+        * does not come up.
+        * This timeout needs only be set when starting the first
+        * (preferred) port.
+        */
+       if (pAC->Rlmt.Port[Para.Para32[0]].LinkDown) {
+               /* PORT_START failed. */
+               for (i = 0; i < pAC->Rlmt.Port[Para.Para32[0]].Net->NumPorts; i++) {
+                       if (!pAC->Rlmt.Port[Para.Para32[0]].Net->Port[i]->PortStarted) {
+                               SkRlmtPortStart(pAC, IoC,
+                                       pAC->Rlmt.Port[Para.Para32[0]].Net->Port[i]->PortNumber);
+                       }
+               }
+       }
+
+       SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+               ("SK_RLMT_PORTSTART_TIMEOUT Event END.\n"))
+}      /* SkRlmtEvtPortStartTim */
+
+
+/******************************************************************************
+ *
+ *     SkRlmtEvtLinkUp - LINK_UP
+ *
+ * Description:
+ *     This routine handles LLINK_UP events.
+ *
+ * Context:
+ *     runtime, pageable?
+ *     may be called after SK_INIT_IO
+ *
+ * Returns:
+ *     Nothing
+ */
+RLMT_STATIC void       SkRlmtEvtLinkUp(
+SK_AC          *pAC,   /* Adapter Context */
+SK_IOC         IoC,    /* I/O Context */
+SK_EVPARA      Para)   /* SK_U32 PortNumber; SK_U32 Undefined */
+{
+       SK_U32                  i;
+       SK_RLMT_PORT    *pRPort;
+       SK_EVPARA               Para2;
+
+       SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+               ("SK_RLMT_LINK_UP Port %d Event BEGIN.\n", Para.Para32[0]))
+
+       pRPort = &pAC->Rlmt.Port[Para.Para32[0]];
+       if (!pRPort->PortStarted) {
+               SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_RLMT_E008, SKERR_RLMT_E008_MSG);
+
+               SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+                               ("SK_RLMT_LINK_UP Event EMPTY.\n"))
+               return;
+       }
+
+       if (!pRPort->LinkDown) {
+               /* RA;:;: Any better solution? */
+               SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+                       ("SK_RLMT_LINK_UP Event EMPTY.\n"))
+               return;
+       }
+
+       SkTimerStop(pAC, IoC, &pRPort->UpTimer);
+       SkTimerStop(pAC, IoC, &pRPort->DownRxTimer);
+       SkTimerStop(pAC, IoC, &pRPort->DownTxTimer);
+
+       /* Do something if timer already fired? */
+
+       pRPort->LinkDown = SK_FALSE;
+       pRPort->PortState = SK_RLMT_PS_GOING_UP;
+       pRPort->GuTimeStamp = SkOsGetTime(pAC);
+       pRPort->BcTimeStamp = 0;
+       pRPort->Net->LinksUp++;
+       if (pRPort->Net->LinksUp == 1) {
+               SK_HWAC_LINK_LED(pAC, IoC, Para.Para32[0], SK_LED_ACTIVE);
+       }
+       else {
+               SK_HWAC_LINK_LED(pAC, IoC, Para.Para32[0], SK_LED_STANDBY);
+       }
+
+       for (i = 0; i < pRPort->Net->NumPorts; i++) {
+               if (!pRPort->Net->Port[i]->PortStarted) {
+                       SkRlmtPortStart(pAC, IoC, pRPort->Net->Port[i]->PortNumber);
+               }
+       }
+
+       SkRlmtCheckSwitch(pAC, IoC, pRPort->Net->NetNumber);
+
+       if (pRPort->Net->LinksUp >= 2) {
+               if (pRPort->Net->RlmtMode & SK_RLMT_CHECK_LOC_LINK) {
+                       /* Build the check chain. */
+                       SkRlmtBuildCheckChain(pAC, pRPort->Net->NetNumber);
+               }
+       }
+
+       /* If the first link comes up, start the periodical RLMT timeout. */
+       if (pRPort->Net->NumPorts > 1 && pRPort->Net->LinksUp == 1 &&
+               (pRPort->Net->RlmtMode & SK_RLMT_CHECK_OTHERS) != 0) {
+               Para2.Para32[0] = pRPort->Net->NetNumber;
+               Para2.Para32[1] = (SK_U32)-1;
+               SkTimerStart(pAC, IoC, &pRPort->Net->LocTimer,
+                       pRPort->Net->TimeoutValue, SKGE_RLMT, SK_RLMT_TIM, Para2);
+       }
+
+       Para2 = Para;
+       Para2.Para32[1] = (SK_U32)-1;
+       SkTimerStart(pAC, IoC, &pRPort->UpTimer, SK_RLMT_PORTUP_TIM_VAL,
+               SKGE_RLMT, SK_RLMT_PORTUP_TIM, Para2);
+       
+       /* Later: if (pAC->Rlmt.RlmtMode & SK_RLMT_CHECK_LOC_LINK) && */
+       if ((pRPort->Net->RlmtMode & SK_RLMT_TRANSPARENT) == 0 &&
+               (pRPort->Net->RlmtMode & SK_RLMT_CHECK_LINK) != 0 &&
+               (Para2.pParaPtr =
+                       SkRlmtBuildPacket(pAC, IoC, Para.Para32[0], SK_PACKET_ANNOUNCE,
+                       &pAC->Addr.Port[Para.Para32[0]].CurrentMacAddress, &SkRlmtMcAddr)
+               ) != NULL) {
+               /* Send "new" packet to RLMT multicast address. */
+               SkEventQueue(pAC, SKGE_DRV, SK_DRV_RLMT_SEND, Para2);
+       }
+
+       if (pRPort->Net->RlmtMode & SK_RLMT_CHECK_SEG) {
+               if ((Para2.pParaPtr =
+                       SkRlmtBuildSpanningTreePacket(pAC, IoC, Para.Para32[0])) != NULL) {
+                       pAC->Rlmt.Port[Para.Para32[0]].RootIdSet = SK_FALSE;
+                       pRPort->Net->CheckingState |=
+                               SK_RLMT_RCS_SEG | SK_RLMT_RCS_REPORT_SEG;
+
+                       SkEventQueue(pAC, SKGE_DRV, SK_DRV_RLMT_SEND, Para2);
+
+                       Para.Para32[1] = (SK_U32)-1;
+                       SkTimerStart(pAC, IoC, &pRPort->Net->SegTimer,
+                               SK_RLMT_SEG_TO_VAL, SKGE_RLMT, SK_RLMT_SEG_TIM, Para);
+               }
+       }
+
+       SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+               ("SK_RLMT_LINK_UP Event END.\n"))
+}      /* SkRlmtEvtLinkUp */
+
+
+/******************************************************************************
+ *
+ *     SkRlmtEvtPortUpTim - PORT_UP_TIM
+ *
+ * Description:
+ *     This routine handles PORT_UP_TIM events.
+ *
+ * Context:
+ *     runtime, pageable?
+ *     may be called after SK_INIT_IO
+ *
+ * Returns:
+ *     Nothing
+ */
+RLMT_STATIC void       SkRlmtEvtPortUpTim(
+SK_AC          *pAC,   /* Adapter Context */
+SK_IOC         IoC,    /* I/O Context */
+SK_EVPARA      Para)   /* SK_U32 PortNumber; SK_U32 -1 */
+{
+       SK_RLMT_PORT    *pRPort;
+
+       SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+               ("SK_RLMT_PORTUP_TIM Port %d Event BEGIN.\n", Para.Para32[0]))
+
+       if (Para.Para32[1] != (SK_U32)-1) {
+               SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+                       ("Bad Parameter.\n"))
+               SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+                       ("SK_RLMT_PORTUP_TIM Event EMPTY.\n"))
+               return;
+       }
+
+       pRPort = &pAC->Rlmt.Port[Para.Para32[0]];
+       if (pRPort->LinkDown || (pRPort->PortState == SK_RLMT_PS_UP)) {
+               SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+                       ("SK_RLMT_PORTUP_TIM Port %d Event EMPTY.\n", Para.Para32[0]))
+               return;
+       }
+
+       pRPort->PortDown = SK_FALSE;
+       pRPort->PortState = SK_RLMT_PS_UP;
+       pRPort->Net->PortsUp++;
+       if (pRPort->Net->RlmtState != SK_RLMT_RS_INIT) {
+               if (pAC->Rlmt.NumNets <= 1) {
+                       SkRlmtCheckSwitch(pAC, IoC, pRPort->Net->NetNumber);
+               }
+               SkEventQueue(pAC, SKGE_PNMI, SK_PNMI_EVT_RLMT_PORT_UP, Para);
+       }
+
+       SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+               ("SK_RLMT_PORTUP_TIM Event END.\n"))
+}      /* SkRlmtEvtPortUpTim */
+
+
+/******************************************************************************
+ *
+ *     SkRlmtEvtPortDownTim - PORT_DOWN_*
+ *
+ * Description:
+ *     This routine handles PORT_DOWN_* events.
+ *
+ * Context:
+ *     runtime, pageable?
+ *     may be called after SK_INIT_IO
+ *
+ * Returns:
+ *     Nothing
+ */
+RLMT_STATIC void       SkRlmtEvtPortDownX(
+SK_AC          *pAC,   /* Adapter Context */
+SK_IOC         IoC,    /* I/O Context */
+SK_U32         Event,  /* Event code */
+SK_EVPARA      Para)   /* SK_U32 PortNumber; SK_U32 -1 */
+{
+       SK_RLMT_PORT    *pRPort;
+
+       SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+               ("SK_RLMT_PORTDOWN* Port %d Event (%d) BEGIN.\n",
+                       Para.Para32[0], Event))
+
+       if (Para.Para32[1] != (SK_U32)-1) {
+               SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+                       ("Bad Parameter.\n"))
+               SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+                       ("SK_RLMT_PORTDOWN* Event EMPTY.\n"))
+               return;
+       }
+
+       pRPort = &pAC->Rlmt.Port[Para.Para32[0]];
+       if (!pRPort->PortStarted || (Event == SK_RLMT_PORTDOWN_TX_TIM &&
+               !(pRPort->CheckingState & SK_RLMT_PCS_TX))) {
+               SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+                       ("SK_RLMT_PORTDOWN* Event (%d) EMPTY.\n", Event))
+               return;
+       }
+       
+       /* Stop port's timers. */
+       SkTimerStop(pAC, IoC, &pRPort->UpTimer);
+       SkTimerStop(pAC, IoC, &pRPort->DownRxTimer);
+       SkTimerStop(pAC, IoC, &pRPort->DownTxTimer);
+
+       if (pRPort->PortState != SK_RLMT_PS_LINK_DOWN) {
+               pRPort->PortState = SK_RLMT_PS_DOWN;
+       }
+
+       if (!pRPort->PortDown) {
+               pRPort->Net->PortsUp--;
+               pRPort->PortDown = SK_TRUE;
+               SkEventQueue(pAC, SKGE_PNMI, SK_PNMI_EVT_RLMT_PORT_DOWN, Para);
+       }
+
+       pRPort->PacketsPerTimeSlot = 0;
+       /* pRPort->DataPacketsPerTimeSlot = 0; */
+       pRPort->BpduPacketsPerTimeSlot = 0;
+       pRPort->BcTimeStamp = 0;
+
+       /*
+        * RA;:;: To be checked:
+        * - actions at RLMT_STOP: We should not switch anymore.
+        */
+       if (pRPort->Net->RlmtState != SK_RLMT_RS_INIT) {
+               if (Para.Para32[0] ==
+                       pRPort->Net->Port[pRPort->Net->ActivePort]->PortNumber) {
+                       /* Active Port went down. */
+                       SkRlmtCheckSwitch(pAC, IoC, pRPort->Net->NetNumber);
+               }
+       }
+
+       SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+               ("SK_RLMT_PORTDOWN* Event (%d) END.\n", Event))
+}      /* SkRlmtEvtPortDownX */
+
+
+/******************************************************************************
+ *
+ *     SkRlmtEvtLinkDown - LINK_DOWN
+ *
+ * Description:
+ *     This routine handles LINK_DOWN events.
+ *
+ * Context:
+ *     runtime, pageable?
+ *     may be called after SK_INIT_IO
+ *
+ * Returns:
+ *     Nothing
+ */
+RLMT_STATIC void       SkRlmtEvtLinkDown(
+SK_AC          *pAC,   /* Adapter Context */
+SK_IOC         IoC,    /* I/O Context */
+SK_EVPARA      Para)   /* SK_U32 PortNumber; SK_U32 Undefined */
+{
+       SK_RLMT_PORT    *pRPort;
+
+       pRPort = &pAC->Rlmt.Port[Para.Para32[0]];
+       SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+               ("SK_RLMT_LINK_DOWN Port %d Event BEGIN.\n", Para.Para32[0]))
+
+       if (!pAC->Rlmt.Port[Para.Para32[0]].LinkDown) {
+               pRPort->Net->LinksUp--;
+               pRPort->LinkDown = SK_TRUE;
+               pRPort->PortState = SK_RLMT_PS_LINK_DOWN;
+               SK_HWAC_LINK_LED(pAC, IoC, Para.Para32[0], SK_LED_OFF);
+
+               if ((pRPort->Net->RlmtMode & SK_RLMT_CHECK_LOC_LINK) != 0) {
+                       /* Build the check chain. */
+                       SkRlmtBuildCheckChain(pAC, pRPort->Net->NetNumber);
+               }
+
+               /* Ensure that port is marked down. */
+               Para.Para32[1] = -1;
+               (void)SkRlmtEvent(pAC, IoC, SK_RLMT_PORTDOWN, Para);
+       }
+
+       SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+               ("SK_RLMT_LINK_DOWN Event END.\n"))
+}      /* SkRlmtEvtLinkDown */
+
+
+/******************************************************************************
+ *
+ *     SkRlmtEvtPortAddr - PORT_ADDR
+ *
+ * Description:
+ *     This routine handles PORT_ADDR events.
+ *
+ * Context:
+ *     runtime, pageable?
+ *     may be called after SK_INIT_IO
+ *
+ * Returns:
+ *     Nothing
+ */
+RLMT_STATIC void       SkRlmtEvtPortAddr(
+SK_AC          *pAC,   /* Adapter Context */
+SK_IOC         IoC,    /* I/O Context */
+SK_EVPARA      Para)   /* SK_U32 PortNumber; SK_U32 -1 */
+{
+       SK_U32                  i, j;
+       SK_RLMT_PORT    *pRPort;
+       SK_MAC_ADDR             *pOldMacAddr;
+       SK_MAC_ADDR             *pNewMacAddr;
+
+       SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+               ("SK_RLMT_PORT_ADDR Port %d Event BEGIN.\n", Para.Para32[0]))
+
+       if (Para.Para32[1] != (SK_U32)-1) {
+               SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+                       ("Bad Parameter.\n"))
+               SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+                       ("SK_RLMT_PORT_ADDR Event EMPTY.\n"))
+               return;
+       }
+
+       /* Port's physical MAC address changed. */
+       pOldMacAddr = &pAC->Addr.Port[Para.Para32[0]].PreviousMacAddress;
+       pNewMacAddr = &pAC->Addr.Port[Para.Para32[0]].CurrentMacAddress;
+
+       /*
+        * NOTE: This is not scalable for solutions where ports are
+        *       checked remotely.  There, we need to send an RLMT
+        *       address change packet - and how do we ensure delivery?
+        */
+       for (i = 0; i < (SK_U32)pAC->GIni.GIMacsFound; i++) {
+               pRPort = &pAC->Rlmt.Port[i];
+               for (j = 0; j < pRPort->PortsChecked; j++) {
+                       if (SK_ADDR_EQUAL(
+                               pRPort->PortCheck[j].CheckAddr.a, pOldMacAddr->a)) {
+                               pRPort->PortCheck[j].CheckAddr = *pNewMacAddr;
+                       }
+               }
+       }
+
+       SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+                       ("SK_RLMT_PORT_ADDR Event END.\n"))
+}      /* SkRlmtEvtPortAddr */
+
+
+/******************************************************************************
+ *
+ *     SkRlmtEvtStart - START
+ *
+ * Description:
+ *     This routine handles START events.
+ *
+ * Context:
+ *     runtime, pageable?
+ *     may be called after SK_INIT_IO
+ *
+ * Returns:
+ *     Nothing
+ */
+RLMT_STATIC void       SkRlmtEvtStart(
+SK_AC          *pAC,   /* Adapter Context */
+SK_IOC         IoC,    /* I/O Context */
+SK_EVPARA      Para)   /* SK_U32 NetNumber; SK_U32 -1 */
+{
+       SK_EVPARA       Para2;
+       SK_U32          PortIdx;
+       SK_U32          PortNumber;
+
+       SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+               ("SK_RLMT_START Net %d Event BEGIN.\n", Para.Para32[0]))
+
+       if (Para.Para32[1] != (SK_U32)-1) {
+               SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+                       ("Bad Parameter.\n"))
+               SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+                       ("SK_RLMT_START Event EMPTY.\n"))
+               return;
+       }
+
+       if (Para.Para32[0] >= pAC->Rlmt.NumNets) {
+               SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+                       ("Bad NetNumber %d.\n", Para.Para32[0]))
+               SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+                       ("SK_RLMT_START Event EMPTY.\n"))
+               return;
+       }
+
+       if (pAC->Rlmt.Net[Para.Para32[0]].RlmtState != SK_RLMT_RS_INIT) {
+               SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+                       ("SK_RLMT_START Event EMPTY.\n"))
+               return;
+       }
+
+       if (pAC->Rlmt.NetsStarted >= pAC->Rlmt.NumNets) {
+               SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+                       ("All nets should have been started.\n"))
+               SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+                       ("SK_RLMT_START Event EMPTY.\n"))
+               return;
+       }
+
+       if (pAC->Rlmt.Net[Para.Para32[0]].PrefPort >=
+               pAC->Rlmt.Net[Para.Para32[0]].NumPorts) {
+               SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_RLMT_E009, SKERR_RLMT_E009_MSG);
+
+               /* Change PrefPort to internal default. */
+               Para2.Para32[0] = 0xFFFFFFFF;
+               Para2.Para32[1] = Para.Para32[0];
+               (void)SkRlmtEvent(pAC, IoC, SK_RLMT_PREFPORT_CHANGE, Para2);
+       }
+
+       PortIdx = pAC->Rlmt.Net[Para.Para32[0]].PrefPort;
+       PortNumber = pAC->Rlmt.Net[Para.Para32[0]].Port[PortIdx]->PortNumber;
+
+       pAC->Rlmt.Net[Para.Para32[0]].LinksUp = 0;
+       pAC->Rlmt.Net[Para.Para32[0]].PortsUp = 0;
+       pAC->Rlmt.Net[Para.Para32[0]].CheckingState = 0;
+       pAC->Rlmt.Net[Para.Para32[0]].RlmtState = SK_RLMT_RS_NET_DOWN;
+
+       /* Start preferred port. */
+       SkRlmtPortStart(pAC, IoC, PortNumber);
+
+       /* Start Timer (for first port only). */
+       Para2.Para32[0] = PortNumber;
+       Para2.Para32[1] = (SK_U32)-1;
+       SkTimerStart(pAC, IoC, &pAC->Rlmt.Port[PortNumber].UpTimer,
+               SK_RLMT_PORTSTART_TIM_VAL, SKGE_RLMT, SK_RLMT_PORTSTART_TIM, Para2);
+
+       pAC->Rlmt.NetsStarted++;
+
+       SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+                       ("SK_RLMT_START Event END.\n"))
+}      /* SkRlmtEvtStart */
+
+
+/******************************************************************************
+ *
+ *     SkRlmtEvtStop - STOP
+ *
+ * Description:
+ *     This routine handles STOP events.
+ *
+ * Context:
+ *     runtime, pageable?
+ *     may be called after SK_INIT_IO
+ *
+ * Returns:
+ *     Nothing
+ */
+RLMT_STATIC void       SkRlmtEvtStop(
+SK_AC          *pAC,   /* Adapter Context */
+SK_IOC         IoC,    /* I/O Context */
+SK_EVPARA      Para)   /* SK_U32 NetNumber; SK_U32 -1 */
+{
+       SK_EVPARA       Para2;
+       SK_U32          PortNumber;
+       SK_U32          i;
+
+       SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+               ("SK_RLMT_STOP Net %d Event BEGIN.\n", Para.Para32[0]))
+
+       if (Para.Para32[1] != (SK_U32)-1) {
+               SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+                       ("Bad Parameter.\n"))
+               SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+                       ("SK_RLMT_STOP Event EMPTY.\n"))
+               return;
+       }
+
+       if (Para.Para32[0] >= pAC->Rlmt.NumNets) {
+               SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+                       ("Bad NetNumber %d.\n", Para.Para32[0]))
+               SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+                       ("SK_RLMT_STOP Event EMPTY.\n"))
+               return;
+       }
+
+       if (pAC->Rlmt.Net[Para.Para32[0]].RlmtState == SK_RLMT_RS_INIT) {
+               SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+                       ("SK_RLMT_STOP Event EMPTY.\n"))
+               return;
+       }
+
+       if (pAC->Rlmt.NetsStarted == 0) {
+               SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+                       ("All nets are stopped.\n"))
+               SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+                       ("SK_RLMT_STOP Event EMPTY.\n"))
+               return;
+       }
+
+       /* Stop RLMT timers. */
+       SkTimerStop(pAC, IoC, &pAC->Rlmt.Net[Para.Para32[0]].LocTimer);
+       SkTimerStop(pAC, IoC, &pAC->Rlmt.Net[Para.Para32[0]].SegTimer);
+
+       /* Stop net. */
+       pAC->Rlmt.Net[Para.Para32[0]].RlmtState = SK_RLMT_RS_INIT;
+       pAC->Rlmt.Net[Para.Para32[0]].RootIdSet = SK_FALSE;
+       Para2.Para32[0] = SK_RLMT_NET_DOWN_FINAL;
+       Para2.Para32[1] = Para.Para32[0];                       /* Net# */
+       SkEventQueue(pAC, SKGE_DRV, SK_DRV_NET_DOWN, Para2);
+
+       /* Stop ports. */
+       for (i = 0; i < pAC->Rlmt.Net[Para.Para32[0]].NumPorts; i++) {
+               PortNumber = pAC->Rlmt.Net[Para.Para32[0]].Port[i]->PortNumber;
+               if (pAC->Rlmt.Port[PortNumber].PortState != SK_RLMT_PS_INIT) {
+                       SkTimerStop(pAC, IoC, &pAC->Rlmt.Port[PortNumber].UpTimer);
+                       SkTimerStop(pAC, IoC, &pAC->Rlmt.Port[PortNumber].DownRxTimer);
+                       SkTimerStop(pAC, IoC, &pAC->Rlmt.Port[PortNumber].DownTxTimer);
+
+                       pAC->Rlmt.Port[PortNumber].PortState = SK_RLMT_PS_INIT;
+                       pAC->Rlmt.Port[PortNumber].RootIdSet = SK_FALSE;
+                       pAC->Rlmt.Port[PortNumber].PortStarted = SK_FALSE;
+                       Para2.Para32[0] = PortNumber;
+                       Para2.Para32[1] = (SK_U32)-1;
+                       SkEventQueue(pAC, SKGE_HWAC, SK_HWEV_PORT_STOP, Para2);
+               }
+       }
+
+       pAC->Rlmt.NetsStarted--;
+
+       SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+               ("SK_RLMT_STOP Event END.\n"))
+}      /* SkRlmtEvtStop */
+
+
+/******************************************************************************
+ *
+ *     SkRlmtEvtTim - TIM
+ *
+ * Description:
+ *     This routine handles TIM events.
+ *
+ * Context:
+ *     runtime, pageable?
+ *     may be called after SK_INIT_IO
+ *
+ * Returns:
+ *     Nothing
+ */
+RLMT_STATIC void       SkRlmtEvtTim(
+SK_AC          *pAC,   /* Adapter Context */
+SK_IOC         IoC,    /* I/O Context */
+SK_EVPARA      Para)   /* SK_U32 NetNumber; SK_U32 -1 */
+{
+       SK_RLMT_PORT    *pRPort;
+       SK_U32                  Timeout;
+       SK_U32                  NewTimeout;
+       SK_U32                  PortNumber;
+       SK_U32                  i;
+
+       SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+               ("SK_RLMT_TIM Event BEGIN.\n"))
+
+       if (Para.Para32[1] != (SK_U32)-1) {
+               SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+                       ("Bad Parameter.\n"))
+               SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+                       ("SK_RLMT_TIM Event EMPTY.\n"))
+               return;
+       }
+
+       if ((pAC->Rlmt.Net[Para.Para32[0]].RlmtMode & SK_RLMT_CHECK_OTHERS) == 0 ||
+               pAC->Rlmt.Net[Para.Para32[0]].LinksUp == 0) {
+               /* Mode changed or all links down: No more link checking. */
+               return;
+       }
+
+#if 0
+       pAC->Rlmt.SwitchCheckCounter--;
+       if (pAC->Rlmt.SwitchCheckCounter == 0) {
+               pAC->Rlmt.SwitchCheckCounter;
+       }
+#endif /* 0 */
+
+       NewTimeout = SK_RLMT_DEF_TO_VAL;
+       for (i = 0; i < pAC->Rlmt.Net[Para.Para32[0]].NumPorts; i++) {
+               PortNumber = pAC->Rlmt.Net[Para.Para32[0]].Port[i]->PortNumber;
+               pRPort = &pAC->Rlmt.Port[PortNumber];
+               if (!pRPort->LinkDown) {
+                       Timeout = SkRlmtCheckPort(pAC, IoC, PortNumber);
+                       if (Timeout < NewTimeout) {
+                               NewTimeout = Timeout;
+                       }
+
+                       /*
+                        * These counters should be set to 0 for all ports before the
+                        * first frame is sent in the next loop.
+                        */
+                       pRPort->PacketsPerTimeSlot = 0;
+                       /* pRPort->DataPacketsPerTimeSlot = 0; */
+                       pRPort->BpduPacketsPerTimeSlot = 0;
+               }
+       }
+       pAC->Rlmt.Net[Para.Para32[0]].TimeoutValue = NewTimeout;
+
+       if (pAC->Rlmt.Net[Para.Para32[0]].LinksUp > 1) {
+               /*
+                * If checking remote ports, also send packets if
+                *   (LinksUp == 1) &&
+                *   this port checks at least one (remote) port.
+                */
+
+               /*
+                * Must be new loop, as SkRlmtCheckPort can request to
+                * check segmentation when e.g. checking the last port.
+                */
+               for (i = 0; i < pAC->Rlmt.Net[Para.Para32[0]].NumPorts; i++) {
+                       if (!pAC->Rlmt.Net[Para.Para32[0]].Port[i]->LinkDown) {
+                               SkRlmtSend(pAC, IoC,
+                                       pAC->Rlmt.Net[Para.Para32[0]].Port[i]->PortNumber);
+                       }
+               }
+       }
+
+       SkTimerStart(pAC, IoC, &pAC->Rlmt.Net[Para.Para32[0]].LocTimer,
+               pAC->Rlmt.Net[Para.Para32[0]].TimeoutValue, SKGE_RLMT, SK_RLMT_TIM,
+               Para);
+
+       if (pAC->Rlmt.Net[Para.Para32[0]].LinksUp > 1 &&
+               (pAC->Rlmt.Net[Para.Para32[0]].RlmtMode & SK_RLMT_CHECK_SEG) &&
+               (pAC->Rlmt.Net[Para.Para32[0]].CheckingState & SK_RLMT_RCS_START_SEG)) {
+               SkTimerStart(pAC, IoC, &pAC->Rlmt.Net[Para.Para32[0]].SegTimer,
+                       SK_RLMT_SEG_TO_VAL, SKGE_RLMT, SK_RLMT_SEG_TIM, Para);
+               pAC->Rlmt.Net[Para.Para32[0]].CheckingState &= ~SK_RLMT_RCS_START_SEG;
+               pAC->Rlmt.Net[Para.Para32[0]].CheckingState |=
+                       SK_RLMT_RCS_SEG | SK_RLMT_RCS_REPORT_SEG;
+       }
+
+       SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+                       ("SK_RLMT_TIM Event END.\n"))
+}      /* SkRlmtEvtTim */
+
+
+/******************************************************************************
+ *
+ *     SkRlmtEvtSegTim - SEG_TIM
+ *
+ * Description:
+ *     This routine handles SEG_TIM events.
+ *
+ * Context:
+ *     runtime, pageable?
+ *     may be called after SK_INIT_IO
+ *
+ * Returns:
+ *     Nothing
+ */
+RLMT_STATIC void       SkRlmtEvtSegTim(
+SK_AC          *pAC,   /* Adapter Context */
+SK_IOC         IoC,    /* I/O Context */
+SK_EVPARA      Para)   /* SK_U32 NetNumber; SK_U32 -1 */
+{
+#ifdef xDEBUG
+       int j;
+#endif /* DEBUG */
+
+       SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+               ("SK_RLMT_SEG_TIM Event BEGIN.\n"))
+
+       if (Para.Para32[1] != (SK_U32)-1) {
+               SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+                       ("Bad Parameter.\n"))
+               SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+                       ("SK_RLMT_SEG_TIM Event EMPTY.\n"))
+               return;
+       }
+
+#ifdef xDEBUG
+       for (j = 0; j < pAC->Rlmt.Net[Para.Para32[0]].NumPorts; j++) {
+               SK_ADDR_PORT    *pAPort;
+               SK_U32                  k;
+               SK_U16                  *InAddr;
+               SK_U8                   InAddr8[6];
+
+               InAddr = (SK_U16 *)&InAddr8[0];
+               pAPort = pAC->Rlmt.Net[Para.Para32[0]].Port[j]->AddrPort;
+               for (k = 0; k < pAPort->NextExactMatchRlmt; k++) {
+                       /* Get exact match address k from port j. */
+                       XM_INADDR(IoC, pAC->Rlmt.Net[Para.Para32[0]].Port[j]->PortNumber,
+                               XM_EXM(k), InAddr);
+                       SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+                               ("MC address %d on Port %u: %02x %02x %02x %02x %02x %02x --  %02x %02x %02x %02x %02x %02x.\n",
+                                       k, pAC->Rlmt.Net[Para.Para32[0]].Port[j]->PortNumber,
+                                       InAddr8[0], InAddr8[1], InAddr8[2],
+                                       InAddr8[3], InAddr8[4], InAddr8[5],
+                                       pAPort->Exact[k].a[0], pAPort->Exact[k].a[1],
+                                       pAPort->Exact[k].a[2], pAPort->Exact[k].a[3],
+                                       pAPort->Exact[k].a[4], pAPort->Exact[k].a[5]))
+               }
+       }
+#endif /* xDEBUG */
+                               
+       SkRlmtCheckSeg(pAC, IoC, Para.Para32[0]);
+
+       SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+                       ("SK_RLMT_SEG_TIM Event END.\n"))
+}      /* SkRlmtEvtSegTim */
+
+
+/******************************************************************************
+ *
+ *     SkRlmtEvtPacketRx - PACKET_RECEIVED
+ *
+ * Description:
+ *     This routine handles PACKET_RECEIVED events.
+ *
+ * Context:
+ *     runtime, pageable?
+ *     may be called after SK_INIT_IO
+ *
+ * Returns:
+ *     Nothing
+ */
+RLMT_STATIC void       SkRlmtEvtPacketRx(
+SK_AC          *pAC,   /* Adapter Context */
+SK_IOC         IoC,    /* I/O Context */
+SK_EVPARA      Para)   /* SK_MBUF *pMb */
+{
+       SK_MBUF *pMb;
+       SK_MBUF *pNextMb;
+       SK_U32  NetNumber;
+
+       
+       SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+               ("SK_RLMT_PACKET_RECEIVED Event BEGIN.\n"))
+
+       /* Should we ignore frames during port switching? */
+
+#ifdef DEBUG
+       pMb = Para.pParaPtr;
+       if (pMb == NULL) {
+               SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, ("No mbuf.\n"))
+       }
+       else if (pMb->pNext != NULL) {
+               SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+                       ("More than one mbuf or pMb->pNext not set.\n"))
+       }
+#endif /* DEBUG */
+
+       for (pMb = Para.pParaPtr; pMb != NULL; pMb = pNextMb) {
+               pNextMb = pMb->pNext;
+               pMb->pNext = NULL;
+
+               NetNumber = pAC->Rlmt.Port[pMb->PortIdx].Net->NetNumber;
+               if (pAC->Rlmt.Net[NetNumber].RlmtState == SK_RLMT_RS_INIT) {
+                       SkDrvFreeRlmtMbuf(pAC, IoC, pMb);
+               }
+               else {
+                       SkRlmtPacketReceive(pAC, IoC, pMb);
+               }
+       }
+
+       SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+               ("SK_RLMT_PACKET_RECEIVED Event END.\n"))
+}      /* SkRlmtEvtPacketRx */
+
+
+/******************************************************************************
+ *
+ *     SkRlmtEvtStatsClear - STATS_CLEAR
+ *
+ * Description:
+ *     This routine handles STATS_CLEAR events.
+ *
+ * Context:
+ *     runtime, pageable?
+ *     may be called after SK_INIT_IO
+ *
+ * Returns:
+ *     Nothing
+ */
+RLMT_STATIC void       SkRlmtEvtStatsClear(
+SK_AC          *pAC,   /* Adapter Context */
+SK_IOC         IoC,    /* I/O Context */
+SK_EVPARA      Para)   /* SK_U32 NetNumber; SK_U32 -1 */
+{
+       SK_U32                  i;
+       SK_RLMT_PORT    *pRPort;
+
+       SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+               ("SK_RLMT_STATS_CLEAR Event BEGIN.\n"))
+
+       if (Para.Para32[1] != (SK_U32)-1) {
+               SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+                       ("Bad Parameter.\n"))
+               SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+                       ("SK_RLMT_STATS_CLEAR Event EMPTY.\n"))
+               return;
+       }
+
+       if (Para.Para32[0] >= pAC->Rlmt.NumNets) {
+               SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+                       ("Bad NetNumber %d.\n", Para.Para32[0]))
+               SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+                       ("SK_RLMT_STATS_CLEAR Event EMPTY.\n"))
+               return;
+       }
+
+       /* Clear statistics for logical and physical ports. */
+       for (i = 0; i < pAC->Rlmt.Net[Para.Para32[0]].NumPorts; i++) {
+               pRPort =
+                       &pAC->Rlmt.Port[pAC->Rlmt.Net[Para.Para32[0]].Port[i]->PortNumber];
+               pRPort->TxHelloCts = 0;
+               pRPort->RxHelloCts = 0;
+               pRPort->TxSpHelloReqCts = 0;
+               pRPort->RxSpHelloCts = 0;
+       }
+
+       SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+               ("SK_RLMT_STATS_CLEAR Event END.\n"))
+}      /* SkRlmtEvtStatsClear */
+
+
+/******************************************************************************
+ *
+ *     SkRlmtEvtStatsUpdate - STATS_UPDATE
+ *
+ * Description:
+ *     This routine handles STATS_UPDATE events.
+ *
+ * Context:
+ *     runtime, pageable?
+ *     may be called after SK_INIT_IO
+ *
+ * Returns:
+ *     Nothing
+ */
+RLMT_STATIC void       SkRlmtEvtStatsUpdate(
+SK_AC          *pAC,   /* Adapter Context */
+SK_IOC         IoC,    /* I/O Context */
+SK_EVPARA      Para)   /* SK_U32 NetNumber; SK_U32 -1 */
+{
+       SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+               ("SK_RLMT_STATS_UPDATE Event BEGIN.\n"))
+
+       if (Para.Para32[1] != (SK_U32)-1) {
+               SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+                       ("Bad Parameter.\n"))
+               SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+                       ("SK_RLMT_STATS_UPDATE Event EMPTY.\n"))
+               return;
+       }
+
+       if (Para.Para32[0] >= pAC->Rlmt.NumNets) {
+               SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+                       ("Bad NetNumber %d.\n", Para.Para32[0]))
+               SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+                       ("SK_RLMT_STATS_UPDATE Event EMPTY.\n"))
+               return;
+       }
+
+       /* Update statistics - currently always up-to-date. */
+
+       SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+               ("SK_RLMT_STATS_UPDATE Event END.\n"))
+}      /* SkRlmtEvtStatsUpdate */
+
+
+/******************************************************************************
+ *
+ *     SkRlmtEvtPrefportChange - PREFPORT_CHANGE
+ *
+ * Description:
+ *     This routine handles PREFPORT_CHANGE events.
+ *
+ * Context:
+ *     runtime, pageable?
+ *     may be called after SK_INIT_IO
+ *
+ * Returns:
+ *     Nothing
+ */
+RLMT_STATIC void       SkRlmtEvtPrefportChange(
+SK_AC          *pAC,   /* Adapter Context */
+SK_IOC         IoC,    /* I/O Context */
+SK_EVPARA      Para)   /* SK_U32 PortIndex; SK_U32 NetNumber */
+{
+       SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+               ("SK_RLMT_PREFPORT_CHANGE to Port %d Event BEGIN.\n", Para.Para32[0]))
+
+       if (Para.Para32[1] >= pAC->Rlmt.NumNets) {
+               SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+                       ("Bad NetNumber %d.\n", Para.Para32[1]))
+               SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+                       ("SK_RLMT_PREFPORT_CHANGE Event EMPTY.\n"))
+               return;
+       }
+
+       /* 0xFFFFFFFF == auto-mode. */
+       if (Para.Para32[0] == 0xFFFFFFFF) {
+               pAC->Rlmt.Net[Para.Para32[1]].PrefPort = SK_RLMT_DEF_PREF_PORT;
+       }
+       else {
+               if (Para.Para32[0] >= pAC->Rlmt.Net[Para.Para32[1]].NumPorts) {
+                       SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_RLMT_E010, SKERR_RLMT_E010_MSG);
+
+                       SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+                               ("SK_RLMT_PREFPORT_CHANGE Event EMPTY.\n"))
+                       return;
+               }
+
+               pAC->Rlmt.Net[Para.Para32[1]].PrefPort = Para.Para32[0];
+       }
+
+       pAC->Rlmt.Net[Para.Para32[1]].Preference = Para.Para32[0];
+
+       if (pAC->Rlmt.Net[Para.Para32[1]].RlmtState != SK_RLMT_RS_INIT) {
+               SkRlmtCheckSwitch(pAC, IoC, Para.Para32[1]);
+       }
+
+       SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+               ("SK_RLMT_PREFPORT_CHANGE Event END.\n"))
+}      /* SkRlmtEvtPrefportChange */
+
+
+/******************************************************************************
+ *
+ *     SkRlmtEvtSetNets - SET_NETS
+ *
+ * Description:
+ *     This routine handles SET_NETS events.
+ *
+ * Context:
+ *     runtime, pageable?
+ *     may be called after SK_INIT_IO
+ *
+ * Returns:
+ *     Nothing
+ */
+RLMT_STATIC void       SkRlmtEvtSetNets(
+SK_AC          *pAC,   /* Adapter Context */
+SK_IOC         IoC,    /* I/O Context */
+SK_EVPARA      Para)   /* SK_U32 NumNets; SK_U32 -1 */
+{
+       int i;
+
+       SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+               ("SK_RLMT_SET_NETS Event BEGIN.\n"))
+
+       if (Para.Para32[1] != (SK_U32)-1) {
+               SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+                       ("Bad Parameter.\n"))
+               SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+                       ("SK_RLMT_SET_NETS Event EMPTY.\n"))
+               return;
+       }
+
+       if (Para.Para32[0] == 0 || Para.Para32[0] > SK_MAX_NETS ||
+               Para.Para32[0] > (SK_U32)pAC->GIni.GIMacsFound) {
+               SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+                       ("Bad number of nets: %d.\n", Para.Para32[0]))
+               SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+                       ("SK_RLMT_SET_NETS Event EMPTY.\n"))
+               return;
+       }
+
+       if (Para.Para32[0] == pAC->Rlmt.NumNets) {      /* No change. */
+               SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+                       ("SK_RLMT_SET_NETS Event EMPTY.\n"))
+               return;
+       }
+
+       /* Entering and leaving dual mode only allowed while nets are stopped. */
+       if (pAC->Rlmt.NetsStarted > 0) {
+               SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+                       ("Changing dual mode only allowed while all nets are stopped.\n"))
+               SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+                       ("SK_RLMT_SET_NETS Event EMPTY.\n"))
+               return;
+       }
+
+       if (Para.Para32[0] == 1) {
+               if (pAC->Rlmt.NumNets > 1) {
+                       /* Clear logical MAC addr from second net's active port. */
+                       (void)SkAddrOverride(pAC, IoC, pAC->Rlmt.Net[1].Port[pAC->Addr.
+                               Net[1].ActivePort]->PortNumber, NULL, SK_ADDR_CLEAR_LOGICAL);
+                       pAC->Rlmt.Net[1].NumPorts = 0;
+               }
+
+               pAC->Rlmt.NumNets = Para.Para32[0];
+               for (i = 0; (SK_U32)i < pAC->Rlmt.NumNets; i++) {
+                       pAC->Rlmt.Net[i].RlmtState = SK_RLMT_RS_INIT;
+                       pAC->Rlmt.Net[i].RootIdSet = SK_FALSE;
+                       pAC->Rlmt.Net[i].Preference = 0xFFFFFFFF;         /* "Automatic" */
+                       pAC->Rlmt.Net[i].PrefPort = SK_RLMT_DEF_PREF_PORT;
+                       /* Just assuming. */
+                       pAC->Rlmt.Net[i].ActivePort = pAC->Rlmt.Net[i].PrefPort;
+                       pAC->Rlmt.Net[i].RlmtMode = SK_RLMT_DEF_MODE;
+                       pAC->Rlmt.Net[i].TimeoutValue = SK_RLMT_DEF_TO_VAL;
+                       pAC->Rlmt.Net[i].NetNumber = i;
+               }
+
+               pAC->Rlmt.Port[1].Net= &pAC->Rlmt.Net[0];
+               pAC->Rlmt.Net[0].NumPorts = pAC->GIni.GIMacsFound;
+
+               SkEventQueue(pAC, SKGE_PNMI, SK_PNMI_EVT_RLMT_SET_NETS, Para);
+
+               SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+                       ("RLMT: Changed to one net with two ports.\n"))
+       }
+       else if (Para.Para32[0] == 2) {
+               pAC->Rlmt.Port[1].Net= &pAC->Rlmt.Net[1];
+               pAC->Rlmt.Net[1].NumPorts = pAC->GIni.GIMacsFound - 1;
+               pAC->Rlmt.Net[0].NumPorts =
+                       pAC->GIni.GIMacsFound - pAC->Rlmt.Net[1].NumPorts;
+               
+               pAC->Rlmt.NumNets = Para.Para32[0];
+               for (i = 0; (SK_U32)i < pAC->Rlmt.NumNets; i++) {
+                       pAC->Rlmt.Net[i].RlmtState = SK_RLMT_RS_INIT;
+                       pAC->Rlmt.Net[i].RootIdSet = SK_FALSE;
+                       pAC->Rlmt.Net[i].Preference = 0xFFFFFFFF;         /* "Automatic" */
+                       pAC->Rlmt.Net[i].PrefPort = SK_RLMT_DEF_PREF_PORT;
+                       /* Just assuming. */
+                       pAC->Rlmt.Net[i].ActivePort = pAC->Rlmt.Net[i].PrefPort;
+                       pAC->Rlmt.Net[i].RlmtMode = SK_RLMT_DEF_MODE;
+                       pAC->Rlmt.Net[i].TimeoutValue = SK_RLMT_DEF_TO_VAL;
+
+                       pAC->Rlmt.Net[i].NetNumber = i;
+               }
+
+               /* Set logical MAC addr on second net's active port. */
+               (void)SkAddrOverride(pAC, IoC, pAC->Rlmt.Net[1].Port[pAC->Addr.
+                       Net[1].ActivePort]->PortNumber, NULL, SK_ADDR_SET_LOGICAL);
+
+               SkEventQueue(pAC, SKGE_PNMI, SK_PNMI_EVT_RLMT_SET_NETS, Para);
+
+               SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+                       ("RLMT: Changed to two nets with one port each.\n"))
+       }
+       else {
+               /* Not implemented for more than two nets. */
+               SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+                       ("SetNets not implemented for more than two nets.\n"))
+               SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+                       ("SK_RLMT_SET_NETS Event EMPTY.\n"))
+               return;
+       }
+
+       SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+               ("SK_RLMT_SET_NETS Event END.\n"))
+}      /* SkRlmtSetNets */
+
+
+/******************************************************************************
+ *
+ *     SkRlmtEvtModeChange - MODE_CHANGE
+ *
+ * Description:
+ *     This routine handles MODE_CHANGE events.
+ *
+ * Context:
+ *     runtime, pageable?
+ *     may be called after SK_INIT_IO
+ *
+ * Returns:
+ *     Nothing
+ */
+RLMT_STATIC void       SkRlmtEvtModeChange(
+SK_AC          *pAC,   /* Adapter Context */
+SK_IOC         IoC,    /* I/O Context */
+SK_EVPARA      Para)   /* SK_U32 NewMode; SK_U32 NetNumber */
+{
+       SK_EVPARA       Para2;
+       SK_U32          i;
+       SK_U32          PrevRlmtMode;
+
+       SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+               ("SK_RLMT_MODE_CHANGE Event BEGIN.\n"))
+
+       if (Para.Para32[1] >= pAC->Rlmt.NumNets) {
+               SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+                       ("Bad NetNumber %d.\n", Para.Para32[1]))
+               SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+                       ("SK_RLMT_MODE_CHANGE Event EMPTY.\n"))
+               return;
+       }
+
+       Para.Para32[0] |= SK_RLMT_CHECK_LINK;
+
+       if ((pAC->Rlmt.Net[Para.Para32[1]].NumPorts == 1) &&
+               Para.Para32[0] != SK_RLMT_MODE_CLS) {
+               pAC->Rlmt.Net[Para.Para32[1]].RlmtMode = SK_RLMT_MODE_CLS;
+               SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+                       ("Forced RLMT mode to CLS on single port net.\n"))
+               SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+                       ("SK_RLMT_MODE_CHANGE Event EMPTY.\n"))
+               return;
+       }
+
+       /* Update RLMT mode. */
+       PrevRlmtMode = pAC->Rlmt.Net[Para.Para32[1]].RlmtMode;
+       pAC->Rlmt.Net[Para.Para32[1]].RlmtMode = Para.Para32[0];
+
+       if ((PrevRlmtMode & SK_RLMT_CHECK_LOC_LINK) !=
+               (pAC->Rlmt.Net[Para.Para32[1]].RlmtMode & SK_RLMT_CHECK_LOC_LINK)) {
+               /* SK_RLMT_CHECK_LOC_LINK bit changed. */
+               if ((PrevRlmtMode & SK_RLMT_CHECK_OTHERS) == 0 &&
+                       pAC->Rlmt.Net[Para.Para32[1]].NumPorts > 1 &&
+                       pAC->Rlmt.Net[Para.Para32[1]].PortsUp >= 1) {
+                       /* 20001207 RA: Was "PortsUp == 1". */
+                       Para2.Para32[0] = Para.Para32[1];
+                       Para2.Para32[1] = (SK_U32)-1;
+                       SkTimerStart(pAC, IoC, &pAC->Rlmt.Net[Para.Para32[1]].LocTimer,
+                               pAC->Rlmt.Net[Para.Para32[1]].TimeoutValue,
+                               SKGE_RLMT, SK_RLMT_TIM, Para2);
+               }
+       }
+
+       if ((PrevRlmtMode & SK_RLMT_CHECK_SEG) !=
+               (pAC->Rlmt.Net[Para.Para32[1]].RlmtMode & SK_RLMT_CHECK_SEG)) {
+               /* SK_RLMT_CHECK_SEG bit changed. */
+               for (i = 0; i < pAC->Rlmt.Net[Para.Para32[1]].NumPorts; i++) {
+                       (void)SkAddrMcClear(pAC, IoC,
+                               pAC->Rlmt.Net[Para.Para32[1]].Port[i]->PortNumber,
+                               SK_ADDR_PERMANENT | SK_MC_SW_ONLY);
+
+                       /* Add RLMT MC address. */
+                       (void)SkAddrMcAdd(pAC, IoC,
+                               pAC->Rlmt.Net[Para.Para32[1]].Port[i]->PortNumber,
+                               &SkRlmtMcAddr, SK_ADDR_PERMANENT);
+
+                       if ((pAC->Rlmt.Net[Para.Para32[1]].RlmtMode &
+                               SK_RLMT_CHECK_SEG) != 0) {
+                               /* Add BPDU MC address. */
+                               (void)SkAddrMcAdd(pAC, IoC,
+                                       pAC->Rlmt.Net[Para.Para32[1]].Port[i]->PortNumber,
+                                       &BridgeMcAddr, SK_ADDR_PERMANENT);
+
+                               if (pAC->Rlmt.Net[Para.Para32[1]].RlmtState != SK_RLMT_RS_INIT) {
+                                       if (!pAC->Rlmt.Net[Para.Para32[1]].Port[i]->LinkDown &&
+                                               (Para2.pParaPtr = SkRlmtBuildSpanningTreePacket(
+                                               pAC, IoC, i)) != NULL) {
+                                               pAC->Rlmt.Net[Para.Para32[1]].Port[i]->RootIdSet =
+                                                       SK_FALSE;
+                                               SkEventQueue(pAC, SKGE_DRV, SK_DRV_RLMT_SEND, Para2);
+                                       }
+                               }
+                       }
+                       (void)SkAddrMcUpdate(pAC, IoC,
+                               pAC->Rlmt.Net[Para.Para32[1]].Port[i]->PortNumber);
+               }       /* for ... */
+
+               if ((pAC->Rlmt.Net[Para.Para32[1]].RlmtMode & SK_RLMT_CHECK_SEG) != 0) {
+                       Para2.Para32[0] = Para.Para32[1];
+                       Para2.Para32[1] = (SK_U32)-1;
+                       SkTimerStart(pAC, IoC, &pAC->Rlmt.Net[Para.Para32[1]].SegTimer,
+                               SK_RLMT_SEG_TO_VAL, SKGE_RLMT, SK_RLMT_SEG_TIM, Para2);
+               }
+       }       /* SK_RLMT_CHECK_SEG bit changed. */
+
+       SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+                       ("SK_RLMT_MODE_CHANGE Event END.\n"))
+}      /* SkRlmtEvtModeChange */
+
+
+/******************************************************************************
+ *
+ *     SkRlmtEvent - a PORT- or an RLMT-specific event happened
+ *
+ * Description:
+ *     This routine calls subroutines to handle PORT- and RLMT-specific events.
+ *
+ * Context:
+ *     runtime, pageable?
+ *     may be called after SK_INIT_IO
+ *
+ * Returns:
+ *     0
+ */
+int    SkRlmtEvent(
+SK_AC          *pAC,   /* Adapter Context */
+SK_IOC         IoC,    /* I/O Context */
+SK_U32         Event,  /* Event code */
+SK_EVPARA      Para)   /* Event-specific parameter */
+{
+       switch (Event) {
+       
+       /* ----- PORT events ----- */
+
+       case SK_RLMT_PORTSTART_TIM:     /* From RLMT via TIME. */
+               SkRlmtEvtPortStartTim(pAC, IoC, Para);
+               break;
+       case SK_RLMT_LINK_UP:           /* From SIRQ. */
+               SkRlmtEvtLinkUp(pAC, IoC, Para);
+               break;
+       case SK_RLMT_PORTUP_TIM:        /* From RLMT via TIME. */
+               SkRlmtEvtPortUpTim(pAC, IoC, Para);
+               break;
+       case SK_RLMT_PORTDOWN:                  /* From RLMT. */
+       case SK_RLMT_PORTDOWN_RX_TIM:   /* From RLMT via TIME. */
+       case SK_RLMT_PORTDOWN_TX_TIM:   /* From RLMT via TIME. */
+               SkRlmtEvtPortDownX(pAC, IoC, Event, Para);
+               break;
+       case SK_RLMT_LINK_DOWN:         /* From SIRQ. */
+               SkRlmtEvtLinkDown(pAC, IoC, Para);
+               break;
+       case SK_RLMT_PORT_ADDR:         /* From ADDR. */
+               SkRlmtEvtPortAddr(pAC, IoC, Para);
+               break;
+
+       /* ----- RLMT events ----- */
+
+       case SK_RLMT_START:             /* From DRV. */
+               SkRlmtEvtStart(pAC, IoC, Para);
+               break;
+       case SK_RLMT_STOP:              /* From DRV. */
+               SkRlmtEvtStop(pAC, IoC, Para);
+               break;
+       case SK_RLMT_TIM:               /* From RLMT via TIME. */
+               SkRlmtEvtTim(pAC, IoC, Para);
+               break;
+       case SK_RLMT_SEG_TIM:
+               SkRlmtEvtSegTim(pAC, IoC, Para);
+               break;
+       case SK_RLMT_PACKET_RECEIVED:   /* From DRV. */
+               SkRlmtEvtPacketRx(pAC, IoC, Para);
+               break;
+       case SK_RLMT_STATS_CLEAR:       /* From PNMI. */
+               SkRlmtEvtStatsClear(pAC, IoC, Para);
+               break;
+       case SK_RLMT_STATS_UPDATE:      /* From PNMI. */
+               SkRlmtEvtStatsUpdate(pAC, IoC, Para);
+               break;
+       case SK_RLMT_PREFPORT_CHANGE:   /* From PNMI. */
+               SkRlmtEvtPrefportChange(pAC, IoC, Para);
+               break;
+       case SK_RLMT_MODE_CHANGE:       /* From PNMI. */
+               SkRlmtEvtModeChange(pAC, IoC, Para);
+               break;
+       case SK_RLMT_SET_NETS:  /* From DRV. */
+               SkRlmtEvtSetNets(pAC, IoC, Para);
+               break;
+
+       /* ----- Unknown events ----- */
+
+       default:        /* Create error log entry. */
+               SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+                       ("Unknown RLMT Event %d.\n", Event))
+               SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_RLMT_E003, SKERR_RLMT_E003_MSG);
+               break;
+       }       /* switch() */
+
+       return (0);
+}      /* SkRlmtEvent */
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
diff --git a/drivers/net/sk98lin/sktimer.c b/drivers/net/sk98lin/sktimer.c
new file mode 100644 (file)
index 0000000..4e46295
--- /dev/null
@@ -0,0 +1,250 @@
+/******************************************************************************
+ *
+ * Name:       sktimer.c
+ * Project:    Gigabit Ethernet Adapters, Event Scheduler Module
+ * Version:    $Revision: 1.14 $
+ * Date:       $Date: 2003/09/16 13:46:51 $
+ * Purpose:    High level timer functions.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *     (C)Copyright 1998-2002 SysKonnect GmbH.
+ *     (C)Copyright 2002-2003 Marvell.
+ *
+ *     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.
+ *
+ *     The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+
+/*
+ *     Event queue and dispatcher
+ */
+#if (defined(DEBUG) || ((!defined(LINT)) && (!defined(SK_SLIM))))
+static const char SysKonnectFileId[] =
+       "@(#) $Id: sktimer.c,v 1.14 2003/09/16 13:46:51 rschmidt Exp $ (C) Marvell.";
+#endif
+
+#include "h/skdrv1st.h"                /* Driver Specific Definitions */
+#include "h/skdrv2nd.h"                /* Adapter Control- and Driver specific Def. */
+
+#ifdef __C2MAN__
+/*
+       Event queue management.
+
+       General Description:
+
+ */
+intro()
+{}
+#endif
+
+
+/* Forward declaration */
+static void timer_done(SK_AC *pAC,SK_IOC Ioc,int Restart);
+
+
+/*
+ * Inits the software timer
+ *
+ * needs to be called during Init level 1.
+ */
+void   SkTimerInit(
+SK_AC  *pAC,           /* Adapters context */
+SK_IOC Ioc,            /* IoContext */
+int            Level)          /* Init Level */
+{
+       switch (Level) {
+       case SK_INIT_DATA:
+               pAC->Tim.StQueue = NULL;
+               break;
+       case SK_INIT_IO:
+               SkHwtInit(pAC, Ioc);
+               SkTimerDone(pAC, Ioc);
+               break;
+       default:
+               break;
+       }
+}
+
+/*
+ * Stops a high level timer
+ * - If a timer is not in the queue the function returns normally, too.
+ */
+void   SkTimerStop(
+SK_AC          *pAC,           /* Adapters context */
+SK_IOC         Ioc,            /* IoContext */
+SK_TIMER       *pTimer)        /* Timer Pointer to be started */
+{
+       SK_TIMER        **ppTimPrev;
+       SK_TIMER        *pTm;
+
+       /*
+        * remove timer from queue
+        */
+       pTimer->TmActive = SK_FALSE;
+       
+       if (pAC->Tim.StQueue == pTimer && !pTimer->TmNext) {
+               SkHwtStop(pAC, Ioc);
+       }
+       
+       for (ppTimPrev = &pAC->Tim.StQueue; (pTm = *ppTimPrev);
+               ppTimPrev = &pTm->TmNext ) {
+               
+               if (pTm == pTimer) {
+                       /*
+                        * Timer found in queue
+                        * - dequeue it and
+                        * - correct delta of the next timer
+                        */
+                       *ppTimPrev = pTm->TmNext;
+
+                       if (pTm->TmNext) {
+                               /* correct delta of next timer in queue */
+                               pTm->TmNext->TmDelta += pTm->TmDelta;
+                       }
+                       return;
+               }
+       }
+}
+
+/*
+ * Start a high level software timer
+ */
+void   SkTimerStart(
+SK_AC          *pAC,           /* Adapters context */
+SK_IOC         Ioc,            /* IoContext */
+SK_TIMER       *pTimer,        /* Timer Pointer to be started */
+SK_U32         Time,           /* Time value */
+SK_U32         Class,          /* Event Class for this timer */
+SK_U32         Event,          /* Event Value for this timer */
+SK_EVPARA      Para)           /* Event Parameter for this timer */
+{
+       SK_TIMER        **ppTimPrev;
+       SK_TIMER        *pTm;
+       SK_U32          Delta;
+
+       Time /= 16;             /* input is uS, clock ticks are 16uS */
+       
+       if (!Time)
+               Time = 1;
+
+       SkTimerStop(pAC, Ioc, pTimer);
+
+       pTimer->TmClass = Class;
+       pTimer->TmEvent = Event;
+       pTimer->TmPara = Para;
+       pTimer->TmActive = SK_TRUE;
+
+       if (!pAC->Tim.StQueue) {
+               /* First Timer to be started */
+               pAC->Tim.StQueue = pTimer;
+               pTimer->TmNext = NULL;
+               pTimer->TmDelta = Time;
+               
+               SkHwtStart(pAC, Ioc, Time);
+               
+               return;
+       }
+
+       /*
+        * timer correction
+        */
+       timer_done(pAC, Ioc, 0);
+
+       /*
+        * find position in queue
+        */
+       Delta = 0;
+       for (ppTimPrev = &pAC->Tim.StQueue; (pTm = *ppTimPrev);
+               ppTimPrev = &pTm->TmNext ) {
+               
+               if (Delta + pTm->TmDelta > Time) {
+                       /* Position found */
+                       /* Here the timer needs to be inserted. */
+                       break;
+               }
+               Delta += pTm->TmDelta;
+       }
+
+       /* insert in queue */
+       *ppTimPrev = pTimer;
+       pTimer->TmNext = pTm;
+       pTimer->TmDelta = Time - Delta;
+
+       if (pTm) {
+               /* There is a next timer
+                * -> correct its Delta value.
+                */
+               pTm->TmDelta -= pTimer->TmDelta;
+       }
+
+       /* restart with first */
+       SkHwtStart(pAC, Ioc, pAC->Tim.StQueue->TmDelta);
+}
+
+
+void   SkTimerDone(
+SK_AC  *pAC,           /* Adapters context */
+SK_IOC Ioc)            /* IoContext */
+{
+       timer_done(pAC, Ioc, 1);
+}
+
+
+static void    timer_done(
+SK_AC  *pAC,           /* Adapters context */
+SK_IOC Ioc,            /* IoContext */
+int            Restart)        /* Do we need to restart the Hardware timer ? */
+{
+       SK_U32          Delta;
+       SK_TIMER        *pTm;
+       SK_TIMER        *pTComp;        /* Timer completed now now */
+       SK_TIMER        **ppLast;       /* Next field of Last timer to be deq */
+       int             Done = 0;
+
+       Delta = SkHwtRead(pAC, Ioc);
+       
+       ppLast = &pAC->Tim.StQueue;
+       pTm = pAC->Tim.StQueue;
+       while (pTm && !Done) {
+               if (Delta >= pTm->TmDelta) {
+                       /* Timer ran out */
+                       pTm->TmActive = SK_FALSE;
+                       Delta -= pTm->TmDelta;
+                       ppLast = &pTm->TmNext;
+                       pTm = pTm->TmNext;
+               }
+               else {
+                       /* We found the first timer that did not run out */
+                       pTm->TmDelta -= Delta;
+                       Delta = 0;
+                       Done = 1;
+               }
+       }
+       *ppLast = NULL;
+       /*
+        * pTm points to the first Timer that did not run out.
+        * StQueue points to the first Timer that run out.
+        */
+
+       for ( pTComp = pAC->Tim.StQueue; pTComp; pTComp = pTComp->TmNext) {
+               SkEventQueue(pAC,pTComp->TmClass, pTComp->TmEvent, pTComp->TmPara);
+       }
+
+       /* Set head of timer queue to the first timer that did not run out */
+       pAC->Tim.StQueue = pTm;
+
+       if (Restart && pAC->Tim.StQueue) {
+               /* Restart HW timer */
+               SkHwtStart(pAC, Ioc, pAC->Tim.StQueue->TmDelta);
+       }
+}
+
+/* End of file */
diff --git a/drivers/net/sk98lin/skvpd.c b/drivers/net/sk98lin/skvpd.c
new file mode 100644 (file)
index 0000000..1e662aa
--- /dev/null
@@ -0,0 +1,1091 @@
+/******************************************************************************
+ *
+ * Name:       skvpd.c
+ * Project:    GEnesis, PCI Gigabit Ethernet Adapter
+ * Version:    $Revision: 1.37 $
+ * Date:       $Date: 2003/01/13 10:42:45 $
+ * Purpose:    Shared software to read and write VPD data
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *     (C)Copyright 1998-2003 SysKonnect GmbH.
+ *
+ *     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.
+ *
+ *     The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/*
+       Please refer skvpd.txt for information how to include this module
+ */
+static const char SysKonnectFileId[] =
+       "@(#)$Id: skvpd.c,v 1.37 2003/01/13 10:42:45 rschmidt Exp $ (C) SK";
+
+#include "h/skdrv1st.h"
+#include "h/sktypes.h"
+#include "h/skdebug.h"
+#include "h/skdrv2nd.h"
+
+/*
+ * Static functions
+ */
+#ifndef SK_KR_PROTO
+static SK_VPD_PARA     *vpd_find_para(
+       SK_AC   *pAC,
+       const char      *key,
+       SK_VPD_PARA *p);
+#else  /* SK_KR_PROTO */
+static SK_VPD_PARA     *vpd_find_para();
+#endif /* SK_KR_PROTO */
+
+/*
+ * waits for a completion of a VPD transfer
+ * The VPD transfer must complete within SK_TICKS_PER_SEC/16
+ *
+ * returns     0:      success, transfer completes
+ *             error   exit(9) with a error message
+ */
+static int VpdWait(
+SK_AC  *pAC,   /* Adapters context */
+SK_IOC IoC,    /* IO Context */
+int            event)  /* event to wait for (VPD_READ / VPD_write) completion*/
+{
+       SK_U64  start_time;
+       SK_U16  state;
+
+       SK_DBG_MSG(pAC,SK_DBGMOD_VPD, SK_DBGCAT_CTRL,
+               ("VPD wait for %s\n", event?"Write":"Read"));
+       start_time = SkOsGetTime(pAC);
+       do {
+               if (SkOsGetTime(pAC) - start_time > SK_TICKS_PER_SEC) {
+
+                       /* Bug fix AF: Thu Mar 28 2002
+                        * Do not call: VPD_STOP(pAC, IoC);
+                        * A pending VPD read cycle can not be aborted by writing
+                        * VPD_WRITE to the PCI_VPD_ADR_REG (VPD address register).
+                        * Although the write threshold in the OUR-register protects
+                        * VPD read only space from being overwritten this does not
+                        * protect a VPD read from being `converted` into a VPD write
+                        * operation (on the fly). As a consequence the VPD_STOP would
+                        * delete VPD read only data. In case of any problems with the
+                        * I2C bus we exit the loop here. The I2C read operation can
+                        * not be aborted except by a reset (->LR).
+                        */
+                       SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_FATAL | SK_DBGCAT_ERR,
+                               ("ERROR:VPD wait timeout\n"));
+                       return(1);
+               }
+               
+               VPD_IN16(pAC, IoC, PCI_VPD_ADR_REG, &state);
+               
+               SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_CTRL,
+                       ("state = %x, event %x\n",state,event));
+       } while((int)(state & PCI_VPD_FLAG) == event);
+
+       return(0);
+}
+
+#ifdef SKDIAG
+
+/*
+ * Read the dword at address 'addr' from the VPD EEPROM.
+ *
+ * Needed Time:        MIN 1,3 ms      MAX 2,6 ms
+ *
+ * Note: The DWord is returned in the endianess of the machine the routine
+ *       is running on.
+ *
+ * Returns the data read.
+ */
+SK_U32 VpdReadDWord(
+SK_AC  *pAC,   /* Adapters context */
+SK_IOC IoC,    /* IO Context */
+int            addr)   /* VPD address */
+{
+       SK_U32  Rtv;
+
+       /* start VPD read */
+       SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_CTRL,
+               ("VPD read dword at 0x%x\n",addr));
+       addr &= ~VPD_WRITE;             /* ensure the R/W bit is set to read */
+
+       VPD_OUT16(pAC, IoC, PCI_VPD_ADR_REG, (SK_U16)addr);
+
+       /* ignore return code here */
+       (void)VpdWait(pAC, IoC, VPD_READ);
+
+       /* Don't swap here, it's a data stream of bytes */
+       Rtv = 0;
+
+       VPD_IN32(pAC, IoC, PCI_VPD_DAT_REG, &Rtv);
+       
+       SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_CTRL,
+               ("VPD read dword data = 0x%x\n",Rtv));
+       return(Rtv);
+}
+
+#endif /* SKDIAG */
+
+/*
+ *     Read one Stream of 'len' bytes of VPD data, starting at 'addr' from
+ *     or to the I2C EEPROM.
+ *
+ * Returns number of bytes read / written.
+ */
+static int VpdWriteStream(
+SK_AC  *pAC,   /* Adapters context */
+SK_IOC IoC,    /* IO Context */
+char   *buf,   /* data buffer */
+int            Addr,   /* VPD start address */
+int            Len)    /* number of bytes to read / to write */
+{
+       int             i;
+       int             j;
+       SK_U16  AdrReg;
+       int             Rtv;
+       SK_U8   * pComp;        /* Compare pointer */
+       SK_U8   Data;           /* Input Data for Compare */
+
+       /* Init Compare Pointer */
+       pComp = (SK_U8 *) buf;
+
+       for (i = 0; i < Len; i++, buf++) {
+               if ((i%sizeof(SK_U32)) == 0) {
+                       /*
+                        * At the begin of each cycle read the Data Reg
+                        * So it is initialized even if only a few bytes
+                        * are written.
+                        */
+                       AdrReg = (SK_U16) Addr;
+                       AdrReg &= ~VPD_WRITE;   /* READ operation */
+
+                       VPD_OUT16(pAC, IoC, PCI_VPD_ADR_REG, AdrReg);
+
+                       /* Wait for termination */
+                       Rtv = VpdWait(pAC, IoC, VPD_READ);
+                       if (Rtv != 0) {
+                               return(i);
+                       }
+               }
+
+               /* Write current Byte */
+               VPD_OUT8(pAC, IoC, PCI_VPD_DAT_REG + (i%sizeof(SK_U32)),
+                               *(SK_U8*)buf);
+
+               if (((i%sizeof(SK_U32)) == 3) || (i == (Len - 1))) {
+                       /* New Address needs to be written to VPD_ADDR reg */
+                       AdrReg = (SK_U16) Addr;
+                       Addr += sizeof(SK_U32);
+                       AdrReg |= VPD_WRITE;    /* WRITE operation */
+
+                       VPD_OUT16(pAC, IoC, PCI_VPD_ADR_REG, AdrReg);
+
+                       /* Wait for termination */
+                       Rtv = VpdWait(pAC, IoC, VPD_WRITE);
+                       if (Rtv != 0) {
+                               SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR,
+                                       ("Write Timed Out\n"));
+                               return(i - (i%sizeof(SK_U32)));
+                       }
+
+                       /*
+                        * Now re-read to verify
+                        */
+                       AdrReg &= ~VPD_WRITE;   /* READ operation */
+
+                       VPD_OUT16(pAC, IoC, PCI_VPD_ADR_REG, AdrReg);
+
+                       /* Wait for termination */
+                       Rtv = VpdWait(pAC, IoC, VPD_READ);
+                       if (Rtv != 0) {
+                               SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR,
+                                       ("Verify Timed Out\n"));
+                               return(i - (i%sizeof(SK_U32)));
+                       }
+
+                       for (j = 0; j <= (int)(i%sizeof(SK_U32)); j++, pComp++) {
+                               
+                               VPD_IN8(pAC, IoC, PCI_VPD_DAT_REG + j, &Data);
+                               
+                               if (Data != *pComp) {
+                                       /* Verify Error */
+                                       SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR,
+                                               ("WriteStream Verify Error\n"));
+                                       return(i - (i%sizeof(SK_U32)) + j);
+                               }
+                       }
+               }
+       }
+
+       return(Len);
+}
+       
+
+/*
+ *     Read one Stream of 'len' bytes of VPD data, starting at 'addr' from
+ *     or to the I2C EEPROM.
+ *
+ * Returns number of bytes read / written.
+ */
+static int VpdReadStream(
+SK_AC  *pAC,   /* Adapters context */
+SK_IOC IoC,    /* IO Context */
+char   *buf,   /* data buffer */
+int            Addr,   /* VPD start address */
+int            Len)    /* number of bytes to read / to write */
+{
+       int             i;
+       SK_U16  AdrReg;
+       int             Rtv;
+
+       for (i = 0; i < Len; i++, buf++) {
+               if ((i%sizeof(SK_U32)) == 0) {
+                       /* New Address needs to be written to VPD_ADDR reg */
+                       AdrReg = (SK_U16) Addr;
+                       Addr += sizeof(SK_U32);
+                       AdrReg &= ~VPD_WRITE;   /* READ operation */
+
+                       VPD_OUT16(pAC, IoC, PCI_VPD_ADR_REG, AdrReg);
+
+                       /* Wait for termination */
+                       Rtv = VpdWait(pAC, IoC, VPD_READ);
+                       if (Rtv != 0) {
+                               return(i);
+                       }
+               }
+               VPD_IN8(pAC, IoC, PCI_VPD_DAT_REG + (i%sizeof(SK_U32)),
+                       (SK_U8 *)buf);
+       }
+
+       return(Len);
+}
+
+/*
+ *     Read ore writes 'len' bytes of VPD data, starting at 'addr' from
+ *     or to the I2C EEPROM.
+ *
+ * Returns number of bytes read / written.
+ */
+static int VpdTransferBlock(
+SK_AC  *pAC,   /* Adapters context */
+SK_IOC IoC,    /* IO Context */
+char   *buf,   /* data buffer */
+int            addr,   /* VPD start address */
+int            len,    /* number of bytes to read / to write */
+int            dir)    /* transfer direction may be VPD_READ or VPD_WRITE */
+{
+       int             Rtv;    /* Return value */
+       int             vpd_rom_size;
+
+       SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_CTRL,
+               ("VPD %s block, addr = 0x%x, len = %d\n",
+               dir ? "write" : "read", addr, len));
+
+       if (len == 0)
+               return(0);
+
+       vpd_rom_size = pAC->vpd.rom_size;
+       
+       if (addr > vpd_rom_size - 4) {
+               SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR | SK_DBGCAT_FATAL,
+                       ("Address error: 0x%x, exp. < 0x%x\n",
+                       addr, vpd_rom_size - 4));
+               return(0);
+       }
+       
+       if (addr + len > vpd_rom_size) {
+               len = vpd_rom_size - addr;
+               SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR,
+                       ("Warning: len was cut to %d\n", len));
+       }
+
+       if (dir == VPD_READ) {
+               Rtv = VpdReadStream(pAC, IoC, buf, addr, len);
+       }
+       else {
+               Rtv = VpdWriteStream(pAC, IoC, buf, addr, len);
+       }
+
+       return(Rtv);
+}
+
+#ifdef SKDIAG
+
+/*
+ *     Read 'len' bytes of VPD data, starting at 'addr'.
+ *
+ * Returns number of bytes read.
+ */
+int VpdReadBlock(
+SK_AC  *pAC,   /* pAC pointer */
+SK_IOC IoC,    /* IO Context */
+char   *buf,   /* buffer were the data should be stored */
+int            addr,   /* start reading at the VPD address */
+int            len)    /* number of bytes to read */
+{
+       return(VpdTransferBlock(pAC, IoC, buf, addr, len, VPD_READ));
+}
+
+/*
+ *     Write 'len' bytes of *but to the VPD EEPROM, starting at 'addr'.
+ *
+ * Returns number of bytes writes.
+ */
+int VpdWriteBlock(
+SK_AC  *pAC,   /* pAC pointer */
+SK_IOC IoC,    /* IO Context */
+char   *buf,   /* buffer, holds the data to write */
+int            addr,   /* start writing at the VPD address */
+int            len)    /* number of bytes to write */
+{
+       return(VpdTransferBlock(pAC, IoC, buf, addr, len, VPD_WRITE));
+}
+#endif /* SKDIAG */
+
+/*
+ * (re)initialize the VPD buffer
+ *
+ * Reads the VPD data from the EEPROM into the VPD buffer.
+ * Get the remaining read only and read / write space.
+ *
+ * return      0:      success
+ *             1:      fatal VPD error
+ */
+static int VpdInit(
+SK_AC  *pAC,   /* Adapters context */
+SK_IOC IoC)    /* IO Context */
+{
+       SK_VPD_PARA *r, rp;     /* RW or RV */
+       int             i;
+       unsigned char   x;
+       int             vpd_size;
+       SK_U16  dev_id;
+       SK_U32  our_reg2;
+
+       SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_INIT, ("VpdInit .. "));
+       
+       VPD_IN16(pAC, IoC, PCI_DEVICE_ID, &dev_id);
+       
+       VPD_IN32(pAC, IoC, PCI_OUR_REG_2, &our_reg2);
+       
+       pAC->vpd.rom_size = 256 << ((our_reg2 & PCI_VPD_ROM_SZ) >> 14);
+       
+       /*
+        * this function might get used before the hardware is initialized
+        * therefore we cannot always trust in GIChipId
+        */
+       if (((pAC->vpd.v.vpd_status & VPD_VALID) == 0 &&
+               dev_id != VPD_DEV_ID_GENESIS) ||
+               ((pAC->vpd.v.vpd_status & VPD_VALID) != 0 &&
+               !pAC->GIni.GIGenesis)) {
+
+               /* for Yukon the VPD size is always 256 */
+               vpd_size = VPD_SIZE_YUKON;
+       }
+       else {
+               /* Genesis uses the maximum ROM size up to 512 for VPD */
+               if (pAC->vpd.rom_size > VPD_SIZE_GENESIS) {
+                       vpd_size = VPD_SIZE_GENESIS;
+               }
+               else {
+                       vpd_size = pAC->vpd.rom_size;
+               }
+       }
+
+       /* read the VPD data into the VPD buffer */
+       if (VpdTransferBlock(pAC, IoC, pAC->vpd.vpd_buf, 0, vpd_size, VPD_READ)
+               != vpd_size) {
+
+               SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR,
+                       ("Block Read Error\n"));
+               return(1);
+       }
+       
+       pAC->vpd.vpd_size = vpd_size;
+
+       /* Asus K8V Se Deluxe bugfix. Correct VPD content */
+       /* MBo April 2004 */
+       if (((unsigned char)pAC->vpd.vpd_buf[0x3f] == 0x38) &&
+           ((unsigned char)pAC->vpd.vpd_buf[0x40] == 0x3c) &&
+           ((unsigned char)pAC->vpd.vpd_buf[0x41] == 0x45)) {
+               printk("sk98lin: Asus mainboard with buggy VPD? "
+                               "Correcting data.\n");
+               pAC->vpd.vpd_buf[0x40] = 0x38;
+       }
+
+
+       /* find the end tag of the RO area */
+       if (!(r = vpd_find_para(pAC, VPD_RV, &rp))) {
+               SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR | SK_DBGCAT_FATAL,
+                       ("Encoding Error: RV Tag not found\n"));
+               return(1);
+       }
+       
+       if (r->p_val + r->p_len > pAC->vpd.vpd_buf + vpd_size/2) {
+               SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR | SK_DBGCAT_FATAL,
+                       ("Encoding Error: Invalid VPD struct size\n"));
+               return(1);
+       }
+       pAC->vpd.v.vpd_free_ro = r->p_len - 1;
+
+       /* test the checksum */
+       for (i = 0, x = 0; (unsigned)i <= (unsigned)vpd_size/2 - r->p_len; i++) {
+               x += pAC->vpd.vpd_buf[i];
+       }
+       
+       if (x != 0) {
+               /* checksum error */
+               SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR | SK_DBGCAT_FATAL,
+                       ("VPD Checksum Error\n"));
+               return(1);
+       }
+
+       /* find and check the end tag of the RW area */
+       if (!(r = vpd_find_para(pAC, VPD_RW, &rp))) {
+               SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR | SK_DBGCAT_FATAL,
+                       ("Encoding Error: RV Tag not found\n"));
+               return(1);
+       }
+       
+       if (r->p_val < pAC->vpd.vpd_buf + vpd_size/2) {
+               SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR | SK_DBGCAT_FATAL,
+                       ("Encoding Error: Invalid VPD struct size\n"));
+               return(1);
+       }
+       pAC->vpd.v.vpd_free_rw = r->p_len;
+
+       /* everything seems to be ok */
+       if (pAC->GIni.GIChipId != 0) {
+               pAC->vpd.v.vpd_status |= VPD_VALID;
+       }
+
+       SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_INIT,
+               ("done. Free RO = %d, Free RW = %d\n",
+               pAC->vpd.v.vpd_free_ro, pAC->vpd.v.vpd_free_rw));
+
+       return(0);
+}
+
+/*
+ *     find the Keyword 'key' in the VPD buffer and fills the
+ *     parameter struct 'p' with it's values
+ *
+ * returns     *p      success
+ *             0:      parameter was not found or VPD encoding error
+ */
+static SK_VPD_PARA *vpd_find_para(
+SK_AC          *pAC,   /* common data base */
+const char     *key,   /* keyword to find (e.g. "MN") */
+SK_VPD_PARA *p)                /* parameter description struct */
+{
+       char *v ;       /* points to VPD buffer */
+       int max;        /* Maximum Number of Iterations */
+
+       v = pAC->vpd.vpd_buf;
+       max = 128;
+
+       SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_CTRL,
+               ("VPD find para %s .. ",key));
+
+       /* check mandatory resource type ID string (Product Name) */
+       if (*v != (char)RES_ID) {
+               SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR | SK_DBGCAT_FATAL,
+                       ("Error: 0x%x missing\n", RES_ID));
+               return NULL;
+       }
+
+       if (strcmp(key, VPD_NAME) == 0) {
+               p->p_len = VPD_GET_RES_LEN(v);
+               p->p_val = VPD_GET_VAL(v);
+               SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_CTRL,
+                       ("found, len = %d\n", p->p_len));
+               return(p);
+       }
+
+       v += 3 + VPD_GET_RES_LEN(v) + 3;
+       for (;; ) {
+               if (SK_MEMCMP(key,v,2) == 0) {
+                       p->p_len = VPD_GET_VPD_LEN(v);
+                       p->p_val = VPD_GET_VAL(v);
+                       SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_CTRL,
+                               ("found, len = %d\n",p->p_len));
+                       return(p);
+               }
+
+               /* exit when reaching the "RW" Tag or the maximum of itera. */
+               max--;
+               if (SK_MEMCMP(VPD_RW,v,2) == 0 || max == 0) {
+                       break;
+               }
+
+               if (SK_MEMCMP(VPD_RV,v,2) == 0) {
+                       v += 3 + VPD_GET_VPD_LEN(v) + 3;        /* skip VPD-W */
+               }
+               else {
+                       v += 3 + VPD_GET_VPD_LEN(v);
+               }
+               SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_CTRL,
+                       ("scanning '%c%c' len = %d\n",v[0],v[1],v[2]));
+       }
+
+#ifdef DEBUG
+       SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_CTRL, ("not found\n"));
+       if (max == 0) {
+               SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR | SK_DBGCAT_FATAL,
+                       ("Key/Len Encoding error\n"));
+       }
+#endif /* DEBUG */
+       return NULL;
+}
+
+/*
+ *     Move 'n' bytes. Begin with the last byte if 'n' is > 0,
+ *     Start with the last byte if n is < 0.
+ *
+ * returns nothing
+ */
+static void vpd_move_para(
+char   *start,         /* start of memory block */
+char   *end,           /* end of memory block to move */
+int            n)                      /* number of bytes the memory block has to be moved */
+{
+       char *p;
+       int i;          /* number of byte copied */
+
+       if (n == 0)
+               return;
+
+       i = (int) (end - start + 1);
+       if (n < 0) {
+               p = start + n;
+               while (i != 0) {
+                       *p++ = *start++;
+                       i--;
+               }
+       }
+       else {
+               p = end + n;
+               while (i != 0) {
+                       *p-- = *end--;
+                       i--;
+               }
+       }
+}
+
+/*
+ *     setup the VPD keyword 'key' at 'ip'.
+ *
+ * returns nothing
+ */
+static void vpd_insert_key(
+const char     *key,   /* keyword to insert */
+const char     *buf,   /* buffer with the keyword value */
+int            len,            /* length of the value string */
+char   *ip)            /* inseration point */
+{
+       SK_VPD_KEY *p;
+
+       p = (SK_VPD_KEY *) ip;
+       p->p_key[0] = key[0];
+       p->p_key[1] = key[1];
+       p->p_len = (unsigned char) len;
+       SK_MEMCPY(&p->p_val,buf,len);
+}
+
+/*
+ *     Setup the VPD end tag "RV" / "RW".
+ *     Also correct the remaining space variables vpd_free_ro / vpd_free_rw.
+ *
+ * returns     0:      success
+ *             1:      encoding error
+ */
+static int vpd_mod_endtag(
+SK_AC  *pAC,           /* common data base */
+char   *etp)           /* end pointer input position */
+{
+       SK_VPD_KEY *p;
+       unsigned char   x;
+       int     i;
+       int     vpd_size;
+
+       SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_CTRL,
+               ("VPD modify endtag at 0x%x = '%c%c'\n",etp,etp[0],etp[1]));
+
+       vpd_size = pAC->vpd.vpd_size;
+
+       p = (SK_VPD_KEY *) etp;
+
+       if (p->p_key[0] != 'R' || (p->p_key[1] != 'V' && p->p_key[1] != 'W')) {
+               /* something wrong here, encoding error */
+               SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR | SK_DBGCAT_FATAL,
+                       ("Encoding Error: invalid end tag\n"));
+               return(1);
+       }
+       if (etp > pAC->vpd.vpd_buf + vpd_size/2) {
+               /* create "RW" tag */
+               p->p_len = (unsigned char)(pAC->vpd.vpd_buf+vpd_size-etp-3-1);
+               pAC->vpd.v.vpd_free_rw = (int) p->p_len;
+               i = pAC->vpd.v.vpd_free_rw;
+               etp += 3;
+       }
+       else {
+               /* create "RV" tag */
+               p->p_len = (unsigned char)(pAC->vpd.vpd_buf+vpd_size/2-etp-3);
+               pAC->vpd.v.vpd_free_ro = (int) p->p_len - 1;
+
+               /* setup checksum */
+               for (i = 0, x = 0; i < vpd_size/2 - p->p_len; i++) {
+                       x += pAC->vpd.vpd_buf[i];
+               }
+               p->p_val = (char) 0 - x;
+               i = pAC->vpd.v.vpd_free_ro;
+               etp += 4;
+       }
+       while (i) {
+               *etp++ = 0x00;
+               i--;
+       }
+
+       return(0);
+}
+
+/*
+ *     Insert a VPD keyword into the VPD buffer.
+ *
+ *     The keyword 'key' is inserted at the position 'ip' in the
+ *     VPD buffer.
+ *     The keywords behind the input position will
+ *     be moved. The VPD end tag "RV" or "RW" is generated again.
+ *
+ * returns     0:      success
+ *             2:      value string was cut
+ *             4:      VPD full, keyword was not written
+ *             6:      fatal VPD error
+ *
+ */
+static int     VpdSetupPara(
+SK_AC  *pAC,           /* common data base */
+const char     *key,   /* keyword to insert */
+const char     *buf,   /* buffer with the keyword value */
+int            len,            /* length of the keyword value */
+int            type,           /* VPD_RO_KEY or VPD_RW_KEY */
+int            op)                     /* operation to do: ADD_KEY or OWR_KEY */
+{
+       SK_VPD_PARA vp;
+       char    *etp;           /* end tag position */
+       int     free;           /* remaining space in selected area */
+       char    *ip;            /* input position inside the VPD buffer */
+       int     rtv;            /* return code */
+       int     head;           /* additional haeder bytes to move */
+       int     found;          /* additinoal bytes if the keyword was found */
+       int vpd_size;
+
+       SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_CTRL,
+               ("VPD setup para key = %s, val = %s\n",key,buf));
+       
+       vpd_size = pAC->vpd.vpd_size;
+
+       rtv = 0;
+       ip = NULL;
+       if (type == VPD_RW_KEY) {
+               /* end tag is "RW" */
+               free = pAC->vpd.v.vpd_free_rw;
+               etp = pAC->vpd.vpd_buf + (vpd_size - free - 1 - 3);
+       }
+       else {
+               /* end tag is "RV" */
+               free = pAC->vpd.v.vpd_free_ro;
+               etp = pAC->vpd.vpd_buf + (vpd_size/2 - free - 4);
+       }
+       SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_CTRL,
+               ("Free RO = %d, Free RW = %d\n",
+               pAC->vpd.v.vpd_free_ro, pAC->vpd.v.vpd_free_rw));
+
+       head = 0;
+       found = 0;
+       if (op == OWR_KEY) {
+               if (vpd_find_para(pAC, key, &vp)) {
+                       found = 3;
+                       ip = vp.p_val - 3;
+                       free += vp.p_len + 3;
+                       SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_CTRL,
+                               ("Overwrite Key\n"));
+               }
+               else {
+                       op = ADD_KEY;
+                       SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_CTRL,
+                               ("Add Key\n"));
+               }
+       }
+       if (op == ADD_KEY) {
+               ip = etp;
+               vp.p_len = 0;
+               head = 3;
+       }
+
+       if (len + 3 > free) {
+               if (free < 7) {
+                       SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR,
+                               ("VPD Buffer Overflow, keyword not written\n"));
+                       return(4);
+               }
+               /* cut it again */
+               len = free - 3;
+               rtv = 2;
+               SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR,
+                       ("VPD Buffer Full, Keyword was cut\n"));
+       }
+
+       vpd_move_para(ip + vp.p_len + found, etp+2, len-vp.p_len+head);
+       vpd_insert_key(key, buf, len, ip);
+       if (vpd_mod_endtag(pAC, etp + len - vp.p_len + head)) {
+               pAC->vpd.v.vpd_status &= ~VPD_VALID;
+               SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR,
+                       ("VPD Encoding Error\n"));
+               return(6);
+       }
+
+       return(rtv);
+}
+
+
+/*
+ *     Read the contents of the VPD EEPROM and copy it to the
+ *     VPD buffer if not already done.
+ *
+ * return:     A pointer to the vpd_status structure. The structure contains
+ *             this fields.
+ */
+SK_VPD_STATUS *VpdStat(
+SK_AC  *pAC,   /* Adapters context */
+SK_IOC IoC)    /* IO Context */
+{
+       if ((pAC->vpd.v.vpd_status & VPD_VALID) == 0) {
+               (void)VpdInit(pAC, IoC);
+       }
+       return(&pAC->vpd.v);
+}
+
+
+/*
+ *     Read the contents of the VPD EEPROM and copy it to the VPD
+ *     buffer if not already done.
+ *     Scan the VPD buffer for VPD keywords and create the VPD
+ *     keyword list by copying the keywords to 'buf', all after
+ *     each other and terminated with a '\0'.
+ *
+ * Exceptions: o The Resource Type ID String (product name) is called "Name"
+ *             o The VPD end tags 'RV' and 'RW' are not listed
+ *
+ *     The number of copied keywords is counted in 'elements'.
+ *
+ * returns     0:      success
+ *             2:      buffer overfull, one or more keywords are missing
+ *             6:      fatal VPD error
+ *
+ *     example values after returning:
+ *
+ *             buf =   "Name\0PN\0EC\0MN\0SN\0CP\0VF\0VL\0YA\0"
+ *             *len =          30
+ *             *elements =      9
+ */
+int VpdKeys(
+SK_AC  *pAC,           /* common data base */
+SK_IOC IoC,            /* IO Context */
+char   *buf,           /* buffer where to copy the keywords */
+int            *len,           /* buffer length */
+int            *elements)      /* number of keywords returned */
+{
+       char *v;
+       int n;
+
+       SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_RX, ("list VPD keys .. "));
+       *elements = 0;
+       if ((pAC->vpd.v.vpd_status & VPD_VALID) == 0) {
+               if (VpdInit(pAC, IoC) != 0) {
+                       *len = 0;
+                       SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR,
+                               ("VPD Init Error, terminated\n"));
+                       return(6);
+               }
+       }
+
+       if ((signed)strlen(VPD_NAME) + 1 <= *len) {
+               v = pAC->vpd.vpd_buf;
+               strcpy(buf,VPD_NAME);
+               n = strlen(VPD_NAME) + 1;
+               buf += n;
+               *elements = 1;
+               SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_RX,
+                       ("'%c%c' ",v[0],v[1]));
+       }
+       else {
+               *len = 0;
+               SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR,
+                       ("buffer overflow\n"));
+               return(2);
+       }
+
+       v += 3 + VPD_GET_RES_LEN(v) + 3;
+       for (;; ) {
+               /* exit when reaching the "RW" Tag */
+               if (SK_MEMCMP(VPD_RW,v,2) == 0) {
+                       break;
+               }
+
+               if (SK_MEMCMP(VPD_RV,v,2) == 0) {
+                       v += 3 + VPD_GET_VPD_LEN(v) + 3;        /* skip VPD-W */
+                       continue;
+               }
+
+               if (n+3 <= *len) {
+                       SK_MEMCPY(buf,v,2);
+                       buf += 2;
+                       *buf++ = '\0';
+                       n += 3;
+                       v += 3 + VPD_GET_VPD_LEN(v);
+                       *elements += 1;
+                       SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_RX,
+                               ("'%c%c' ",v[0],v[1]));
+               }
+               else {
+                       *len = n;
+                       SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR,
+                               ("buffer overflow\n"));
+                       return(2);
+               }
+       }
+
+       SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_RX, ("\n"));
+       *len = n;
+       return(0);
+}
+
+
+/*
+ *     Read the contents of the VPD EEPROM and copy it to the
+ *     VPD buffer if not already done. Search for the VPD keyword
+ *     'key' and copy its value to 'buf'. Add a terminating '\0'.
+ *     If the value does not fit into the buffer cut it after
+ *     'len' - 1 bytes.
+ *
+ * returns     0:      success
+ *             1:      keyword not found
+ *             2:      value string was cut
+ *             3:      VPD transfer timeout
+ *             6:      fatal VPD error
+ */
+int VpdRead(
+SK_AC          *pAC,   /* common data base */
+SK_IOC         IoC,    /* IO Context */
+const char     *key,   /* keyword to read (e.g. "MN") */
+char           *buf,   /* buffer where to copy the keyword value */
+int                    *len)   /* buffer length */
+{
+       SK_VPD_PARA *p, vp;
+
+       SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_RX, ("VPD read %s .. ", key));
+       if ((pAC->vpd.v.vpd_status & VPD_VALID) == 0) {
+               if (VpdInit(pAC, IoC) != 0) {
+                       *len = 0;
+                       SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR,
+                               ("VPD init error\n"));
+                       return(6);
+               }
+       }
+
+       if ((p = vpd_find_para(pAC, key, &vp)) != NULL) {
+               if (p->p_len > (*(unsigned *)len)-1) {
+                       p->p_len = *len - 1;
+               }
+               SK_MEMCPY(buf, p->p_val, p->p_len);
+               buf[p->p_len] = '\0';
+               *len = p->p_len;
+               SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_RX,
+                       ("%c%c%c%c.., len = %d\n",
+                       buf[0],buf[1],buf[2],buf[3],*len));
+       }
+       else {
+               *len = 0;
+               SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR, ("not found\n"));
+               return(1);
+       }
+       return(0);
+}
+
+
+/*
+ *     Check whether a given key may be written
+ *
+ * returns
+ *     SK_TRUE         Yes it may be written
+ *     SK_FALSE        No it may be written
+ */
+SK_BOOL VpdMayWrite(
+char   *key)   /* keyword to write (allowed values "Yx", "Vx") */
+{
+       if ((*key != 'Y' && *key != 'V') ||
+               key[1] < '0' || key[1] > 'Z' ||
+               (key[1] > '9' && key[1] < 'A') || strlen(key) != 2) {
+
+               return(SK_FALSE);
+       }
+       return(SK_TRUE);
+}
+
+/*
+ *     Read the contents of the VPD EEPROM and copy it to the VPD
+ *     buffer if not already done. Insert/overwrite the keyword 'key'
+ *     in the VPD buffer. Cut the keyword value if it does not fit
+ *     into the VPD read / write area.
+ *
+ * returns     0:      success
+ *             2:      value string was cut
+ *             3:      VPD transfer timeout
+ *             4:      VPD full, keyword was not written
+ *             5:      keyword cannot be written
+ *             6:      fatal VPD error
+ */
+int VpdWrite(
+SK_AC          *pAC,   /* common data base */
+SK_IOC         IoC,    /* IO Context */
+const char     *key,   /* keyword to write (allowed values "Yx", "Vx") */
+const char     *buf)   /* buffer where the keyword value can be read from */
+{
+       int len;                /* length of the keyword to write */
+       int rtv;                /* return code */
+       int rtv2;
+
+       SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_TX,
+               ("VPD write %s = %s\n",key,buf));
+
+       if ((*key != 'Y' && *key != 'V') ||
+               key[1] < '0' || key[1] > 'Z' ||
+               (key[1] > '9' && key[1] < 'A') || strlen(key) != 2) {
+
+               SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR,
+                       ("illegal key tag, keyword not written\n"));
+               return(5);
+       }
+
+       if ((pAC->vpd.v.vpd_status & VPD_VALID) == 0) {
+               if (VpdInit(pAC, IoC) != 0) {
+                       SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR,
+                               ("VPD init error\n"));
+                       return(6);
+               }
+       }
+
+       rtv = 0;
+       len = strlen(buf);
+       if (len > VPD_MAX_LEN) {
+               /* cut it */
+               len = VPD_MAX_LEN;
+               rtv = 2;
+               SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR,
+                       ("keyword too long, cut after %d bytes\n",VPD_MAX_LEN));
+       }
+       if ((rtv2 = VpdSetupPara(pAC, key, buf, len, VPD_RW_KEY, OWR_KEY)) != 0) {
+               SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR,
+                       ("VPD write error\n"));
+               return(rtv2);
+       }
+
+       return(rtv);
+}
+
+/*
+ *     Read the contents of the VPD EEPROM and copy it to the
+ *     VPD buffer if not already done. Remove the VPD keyword
+ *     'key' from the VPD buffer.
+ *     Only the keywords in the read/write area can be deleted.
+ *     Keywords in the read only area cannot be deleted.
+ *
+ * returns     0:      success, keyword was removed
+ *             1:      keyword not found
+ *             5:      keyword cannot be deleted
+ *             6:      fatal VPD error
+ */
+int VpdDelete(
+SK_AC  *pAC,   /* common data base */
+SK_IOC IoC,    /* IO Context */
+char   *key)   /* keyword to read (e.g. "MN") */
+{
+       SK_VPD_PARA *p, vp;
+       char *etp;
+       int     vpd_size;
+
+       vpd_size = pAC->vpd.vpd_size;
+
+       SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_TX,("VPD delete key %s\n",key));
+       if ((pAC->vpd.v.vpd_status & VPD_VALID) == 0) {
+               if (VpdInit(pAC, IoC) != 0) {
+                       SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR,
+                               ("VPD init error\n"));
+                       return(6);
+               }
+       }
+
+       if ((p = vpd_find_para(pAC, key, &vp)) != NULL) {
+               if (p->p_val < pAC->vpd.vpd_buf + vpd_size/2) {
+                       /* try to delete read only keyword */
+                       SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR,
+                               ("cannot delete RO keyword\n"));
+                       return(5);
+               }
+
+               etp = pAC->vpd.vpd_buf + (vpd_size-pAC->vpd.v.vpd_free_rw-1-3);
+
+               vpd_move_para(vp.p_val+vp.p_len, etp+2,
+                       - ((int)(vp.p_len + 3)));
+               if (vpd_mod_endtag(pAC, etp - vp.p_len - 3)) {
+                       pAC->vpd.v.vpd_status &= ~VPD_VALID;
+                       SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR,
+                               ("VPD encoding error\n"));
+                       return(6);
+               }
+       }
+       else {
+               SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR,
+                       ("keyword not found\n"));
+               return(1);
+       }
+
+       return(0);
+}
+
+/*
+ *     If the VPD buffer contains valid data write the VPD
+ *     read/write area back to the VPD EEPROM.
+ *
+ * returns     0:      success
+ *             3:      VPD transfer timeout
+ */
+int VpdUpdate(
+SK_AC  *pAC,   /* Adapters context */
+SK_IOC IoC)    /* IO Context */
+{
+       int vpd_size;
+
+       vpd_size = pAC->vpd.vpd_size;
+
+       SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_TX, ("VPD update .. "));
+       if ((pAC->vpd.v.vpd_status & VPD_VALID) != 0) {
+               if (VpdTransferBlock(pAC, IoC, pAC->vpd.vpd_buf + vpd_size/2,
+                       vpd_size/2, vpd_size/2, VPD_WRITE) != vpd_size/2) {
+
+                       SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR,
+                               ("transfer timed out\n"));
+                       return(3);
+               }
+       }
+       SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_TX, ("done\n"));
+       return(0);
+}
+
diff --git a/drivers/net/sk98lin/skxmac2.c b/drivers/net/sk98lin/skxmac2.c
new file mode 100644 (file)
index 0000000..b4e7502
--- /dev/null
@@ -0,0 +1,4160 @@
+/******************************************************************************
+ *
+ * Name:       skxmac2.c
+ * Project:    Gigabit Ethernet Adapters, Common Modules
+ * Version:    $Revision: 1.102 $
+ * Date:       $Date: 2003/10/02 16:53:58 $
+ * Purpose:    Contains functions to initialize the MACs and PHYs
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *     (C)Copyright 1998-2002 SysKonnect.
+ *     (C)Copyright 2002-2003 Marvell.
+ *
+ *     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.
+ *
+ *     The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+#include "h/skdrv1st.h"
+#include "h/skdrv2nd.h"
+
+/* typedefs *******************************************************************/
+
+/* BCOM PHY magic pattern list */
+typedef struct s_PhyHack {
+       int             PhyReg;         /* Phy register */
+       SK_U16  PhyVal;         /* Value to write */
+} BCOM_HACK;
+
+/* local variables ************************************************************/
+
+#if (defined(DEBUG) || ((!defined(LINT)) && (!defined(SK_SLIM))))
+static const char SysKonnectFileId[] =
+       "@(#) $Id: skxmac2.c,v 1.102 2003/10/02 16:53:58 rschmidt Exp $ (C) Marvell.";
+#endif
+
+#ifdef GENESIS
+static BCOM_HACK BcomRegA1Hack[] = {
+ { 0x18, 0x0c20 }, { 0x17, 0x0012 }, { 0x15, 0x1104 }, { 0x17, 0x0013 },
+ { 0x15, 0x0404 }, { 0x17, 0x8006 }, { 0x15, 0x0132 }, { 0x17, 0x8006 },
+ { 0x15, 0x0232 }, { 0x17, 0x800D }, { 0x15, 0x000F }, { 0x18, 0x0420 },
+ { 0, 0 }
+};
+static BCOM_HACK BcomRegC0Hack[] = {
+ { 0x18, 0x0c20 }, { 0x17, 0x0012 }, { 0x15, 0x1204 }, { 0x17, 0x0013 },
+ { 0x15, 0x0A04 }, { 0x18, 0x0420 },
+ { 0, 0 }
+};
+#endif
+
+/* function prototypes ********************************************************/
+#ifdef GENESIS
+static void    SkXmInitPhyXmac(SK_AC*, SK_IOC, int, SK_BOOL);
+static void    SkXmInitPhyBcom(SK_AC*, SK_IOC, int, SK_BOOL);
+static int     SkXmAutoNegDoneXmac(SK_AC*, SK_IOC, int);
+static int     SkXmAutoNegDoneBcom(SK_AC*, SK_IOC, int);
+#endif /* GENESIS */
+#ifdef YUKON
+static void    SkGmInitPhyMarv(SK_AC*, SK_IOC, int, SK_BOOL);
+static int     SkGmAutoNegDoneMarv(SK_AC*, SK_IOC, int);
+#endif /* YUKON */
+#ifdef OTHER_PHY
+static void    SkXmInitPhyLone(SK_AC*, SK_IOC, int, SK_BOOL);
+static void    SkXmInitPhyNat (SK_AC*, SK_IOC, int, SK_BOOL);
+static int     SkXmAutoNegDoneLone(SK_AC*, SK_IOC, int);
+static int     SkXmAutoNegDoneNat (SK_AC*, SK_IOC, int);
+#endif /* OTHER_PHY */
+
+
+#ifdef GENESIS
+/******************************************************************************
+ *
+ *     SkXmPhyRead() - Read from XMAC PHY register
+ *
+ * Description:        reads a 16-bit word from XMAC PHY or ext. PHY
+ *
+ * Returns:
+ *     nothing
+ */
+void SkXmPhyRead(
+SK_AC  *pAC,                   /* Adapter Context */
+SK_IOC IoC,                    /* I/O Context */
+int            Port,                   /* Port Index (MAC_1 + n) */
+int            PhyReg,                 /* Register Address (Offset) */
+SK_U16 SK_FAR *pVal)   /* Pointer to Value */
+{
+       SK_U16          Mmu;
+       SK_GEPORT       *pPrt;
+
+       pPrt = &pAC->GIni.GP[Port];
+       
+       /* write the PHY register's address */
+       XM_OUT16(IoC, Port, XM_PHY_ADDR, PhyReg | pPrt->PhyAddr);
+       
+       /* get the PHY register's value */
+       XM_IN16(IoC, Port, XM_PHY_DATA, pVal);
+       
+       if (pPrt->PhyType != SK_PHY_XMAC) {
+               do {
+                       XM_IN16(IoC, Port, XM_MMU_CMD, &Mmu);
+                       /* wait until 'Ready' is set */
+               } while ((Mmu & XM_MMU_PHY_RDY) == 0);
+
+               /* get the PHY register's value */
+               XM_IN16(IoC, Port, XM_PHY_DATA, pVal);
+       }
+}      /* SkXmPhyRead */
+
+
+/******************************************************************************
+ *
+ *     SkXmPhyWrite() - Write to XMAC PHY register
+ *
+ * Description:        writes a 16-bit word to XMAC PHY or ext. PHY
+ *
+ * Returns:
+ *     nothing
+ */
+void SkXmPhyWrite(
+SK_AC  *pAC,           /* Adapter Context */
+SK_IOC IoC,            /* I/O Context */
+int            Port,           /* Port Index (MAC_1 + n) */
+int            PhyReg,         /* Register Address (Offset) */
+SK_U16 Val)            /* Value */
+{
+       SK_U16          Mmu;
+       SK_GEPORT       *pPrt;
+
+       pPrt = &pAC->GIni.GP[Port];
+       
+       if (pPrt->PhyType != SK_PHY_XMAC) {
+               do {
+                       XM_IN16(IoC, Port, XM_MMU_CMD, &Mmu);
+                       /* wait until 'Busy' is cleared */
+               } while ((Mmu & XM_MMU_PHY_BUSY) != 0);
+       }
+       
+       /* write the PHY register's address */
+       XM_OUT16(IoC, Port, XM_PHY_ADDR, PhyReg | pPrt->PhyAddr);
+       
+       /* write the PHY register's value */
+       XM_OUT16(IoC, Port, XM_PHY_DATA, Val);
+       
+       if (pPrt->PhyType != SK_PHY_XMAC) {
+               do {
+                       XM_IN16(IoC, Port, XM_MMU_CMD, &Mmu);
+                       /* wait until 'Busy' is cleared */
+               } while ((Mmu & XM_MMU_PHY_BUSY) != 0);
+       }
+}      /* SkXmPhyWrite */
+#endif /* GENESIS */
+
+
+#ifdef YUKON
+/******************************************************************************
+ *
+ *     SkGmPhyRead() - Read from GPHY register
+ *
+ * Description:        reads a 16-bit word from GPHY through MDIO
+ *
+ * Returns:
+ *     nothing
+ */
+void SkGmPhyRead(
+SK_AC  *pAC,                   /* Adapter Context */
+SK_IOC IoC,                    /* I/O Context */
+int            Port,                   /* Port Index (MAC_1 + n) */
+int            PhyReg,                 /* Register Address (Offset) */
+SK_U16 SK_FAR *pVal)   /* Pointer to Value */
+{
+       SK_U16  Ctrl;
+       SK_GEPORT       *pPrt;
+#ifdef VCPU
+       u_long SimCyle;
+       u_long SimLowTime;
+       
+       VCPUgetTime(&SimCyle, &SimLowTime);
+       VCPUprintf(0, "SkGmPhyRead(%u), SimCyle=%u, SimLowTime=%u\n",
+               PhyReg, SimCyle, SimLowTime);
+#endif /* VCPU */
+       
+       pPrt = &pAC->GIni.GP[Port];
+       
+       /* set PHY-Register offset and 'Read' OpCode (= 1) */
+       *pVal = (SK_U16)(GM_SMI_CT_PHY_AD(pPrt->PhyAddr) |
+               GM_SMI_CT_REG_AD(PhyReg) | GM_SMI_CT_OP_RD);
+
+       GM_OUT16(IoC, Port, GM_SMI_CTRL, *pVal);
+
+       GM_IN16(IoC, Port, GM_SMI_CTRL, &Ctrl);
+       
+       /* additional check for MDC/MDIO activity */
+       if ((Ctrl & GM_SMI_CT_BUSY) == 0) {
+               *pVal = 0;
+               return;
+       }
+
+       *pVal |= GM_SMI_CT_BUSY;
+       
+       do {
+#ifdef VCPU
+               VCPUwaitTime(1000);
+#endif /* VCPU */
+
+               GM_IN16(IoC, Port, GM_SMI_CTRL, &Ctrl);
+
+       /* wait until 'ReadValid' is set */
+       } while (Ctrl == *pVal);
+       
+       /* get the PHY register's value */
+       GM_IN16(IoC, Port, GM_SMI_DATA, pVal);
+
+#ifdef VCPU
+       VCPUgetTime(&SimCyle, &SimLowTime);
+       VCPUprintf(0, "VCPUgetTime(), SimCyle=%u, SimLowTime=%u\n",
+               SimCyle, SimLowTime);
+#endif /* VCPU */
+
+}      /* SkGmPhyRead */
+
+
+/******************************************************************************
+ *
+ *     SkGmPhyWrite() - Write to GPHY register
+ *
+ * Description:        writes a 16-bit word to GPHY through MDIO
+ *
+ * Returns:
+ *     nothing
+ */
+void SkGmPhyWrite(
+SK_AC  *pAC,           /* Adapter Context */
+SK_IOC IoC,            /* I/O Context */
+int            Port,           /* Port Index (MAC_1 + n) */
+int            PhyReg,         /* Register Address (Offset) */
+SK_U16 Val)            /* Value */
+{
+       SK_U16  Ctrl;
+       SK_GEPORT       *pPrt;
+#ifdef VCPU
+       SK_U32  DWord;
+       u_long  SimCyle;
+       u_long  SimLowTime;
+       
+       VCPUgetTime(&SimCyle, &SimLowTime);
+       VCPUprintf(0, "SkGmPhyWrite(Reg=%u, Val=0x%04x), SimCyle=%u, SimLowTime=%u\n",
+               PhyReg, Val, SimCyle, SimLowTime);
+#endif /* VCPU */
+       
+       pPrt = &pAC->GIni.GP[Port];
+       
+       /* write the PHY register's value */
+       GM_OUT16(IoC, Port, GM_SMI_DATA, Val);
+       
+       /* set PHY-Register offset and 'Write' OpCode (= 0) */
+       Val = GM_SMI_CT_PHY_AD(pPrt->PhyAddr) | GM_SMI_CT_REG_AD(PhyReg);
+
+       GM_OUT16(IoC, Port, GM_SMI_CTRL, Val);
+
+       GM_IN16(IoC, Port, GM_SMI_CTRL, &Ctrl);
+       
+       /* additional check for MDC/MDIO activity */
+       if ((Ctrl & GM_SMI_CT_BUSY) == 0) {
+               return;
+       }
+       
+       Val |= GM_SMI_CT_BUSY;
+
+       do {
+#ifdef VCPU
+               /* read Timer value */
+               SK_IN32(IoC, B2_TI_VAL, &DWord);
+
+               VCPUwaitTime(1000);
+#endif /* VCPU */
+
+               GM_IN16(IoC, Port, GM_SMI_CTRL, &Ctrl);
+
+       /* wait until 'Busy' is cleared */
+       } while (Ctrl == Val);
+       
+#ifdef VCPU
+       VCPUgetTime(&SimCyle, &SimLowTime);
+       VCPUprintf(0, "VCPUgetTime(), SimCyle=%u, SimLowTime=%u\n",
+               SimCyle, SimLowTime);
+#endif /* VCPU */
+
+}      /* SkGmPhyWrite */
+#endif /* YUKON */
+
+
+#ifdef SK_DIAG
+/******************************************************************************
+ *
+ *     SkGePhyRead() - Read from PHY register
+ *
+ * Description:        calls a read PHY routine dep. on board type
+ *
+ * Returns:
+ *     nothing
+ */
+void SkGePhyRead(
+SK_AC  *pAC,           /* Adapter Context */
+SK_IOC IoC,            /* I/O Context */
+int            Port,           /* Port Index (MAC_1 + n) */
+int            PhyReg,         /* Register Address (Offset) */
+SK_U16 *pVal)          /* Pointer to Value */
+{
+       void (*r_func)(SK_AC *pAC, SK_IOC IoC, int Port, int Reg, SK_U16 *pVal);
+
+       if (pAC->GIni.GIGenesis) {
+               r_func = SkXmPhyRead;
+       }
+       else {
+               r_func = SkGmPhyRead;
+       }
+       
+       r_func(pAC, IoC, Port, PhyReg, pVal);
+}      /* SkGePhyRead */
+
+
+/******************************************************************************
+ *
+ *     SkGePhyWrite() - Write to PHY register
+ *
+ * Description:        calls a write PHY routine dep. on board type
+ *
+ * Returns:
+ *     nothing
+ */
+void SkGePhyWrite(
+SK_AC  *pAC,           /* Adapter Context */
+SK_IOC IoC,            /* I/O Context */
+int            Port,           /* Port Index (MAC_1 + n) */
+int            PhyReg,         /* Register Address (Offset) */
+SK_U16 Val)            /* Value */
+{
+       void (*w_func)(SK_AC *pAC, SK_IOC IoC, int Port, int Reg, SK_U16 Val);
+
+       if (pAC->GIni.GIGenesis) {
+               w_func = SkXmPhyWrite;
+       }
+       else {
+               w_func = SkGmPhyWrite;
+       }
+       
+       w_func(pAC, IoC, Port, PhyReg, Val);
+}      /* SkGePhyWrite */
+#endif /* SK_DIAG */
+
+
+/******************************************************************************
+ *
+ *     SkMacPromiscMode() - Enable / Disable Promiscuous Mode
+ *
+ * Description:
+ *   enables / disables promiscuous mode by setting Mode Register (XMAC) or
+ *   Receive Control Register (GMAC) dep. on board type        
+ *
+ * Returns:
+ *     nothing
+ */
+void SkMacPromiscMode(
+SK_AC  *pAC,   /* adapter context */
+SK_IOC IoC,    /* IO context */
+int            Port,   /* Port Index (MAC_1 + n) */
+SK_BOOL        Enable) /* Enable / Disable */
+{
+#ifdef YUKON
+       SK_U16  RcReg;
+#endif
+#ifdef GENESIS
+       SK_U32  MdReg;
+#endif 
+
+#ifdef GENESIS
+       if (pAC->GIni.GIGenesis) {
+               
+               XM_IN32(IoC, Port, XM_MODE, &MdReg);
+               /* enable or disable promiscuous mode */
+               if (Enable) {
+                       MdReg |= XM_MD_ENA_PROM;
+               }
+               else {
+                       MdReg &= ~XM_MD_ENA_PROM;
+               }
+               /* setup Mode Register */
+               XM_OUT32(IoC, Port, XM_MODE, MdReg);
+       }
+#endif /* GENESIS */
+       
+#ifdef YUKON
+       if (pAC->GIni.GIYukon) {
+               
+               GM_IN16(IoC, Port, GM_RX_CTRL, &RcReg);
+               
+               /* enable or disable unicast and multicast filtering */
+               if (Enable) {
+                       RcReg &= ~(GM_RXCR_UCF_ENA | GM_RXCR_MCF_ENA);
+               }
+               else {
+                       RcReg |= (GM_RXCR_UCF_ENA | GM_RXCR_MCF_ENA);
+               }
+               /* setup Receive Control Register */
+               GM_OUT16(IoC, Port, GM_RX_CTRL, RcReg);
+       }
+#endif /* YUKON */
+
+}      /* SkMacPromiscMode*/
+
+
+/******************************************************************************
+ *
+ *     SkMacHashing() - Enable / Disable Hashing
+ *
+ * Description:
+ *   enables / disables hashing by setting Mode Register (XMAC) or
+ *   Receive Control Register (GMAC) dep. on board type                
+ *
+ * Returns:
+ *     nothing
+ */
+void SkMacHashing(
+SK_AC  *pAC,   /* adapter context */
+SK_IOC IoC,    /* IO context */
+int            Port,   /* Port Index (MAC_1 + n) */
+SK_BOOL        Enable) /* Enable / Disable */
+{
+#ifdef YUKON
+       SK_U16  RcReg;
+#endif 
+#ifdef GENESIS
+       SK_U32  MdReg;
+#endif
+
+#ifdef GENESIS
+       if (pAC->GIni.GIGenesis) {
+               
+               XM_IN32(IoC, Port, XM_MODE, &MdReg);
+               /* enable or disable hashing */
+               if (Enable) {
+                       MdReg |= XM_MD_ENA_HASH;
+               }
+               else {
+                       MdReg &= ~XM_MD_ENA_HASH;
+               }
+               /* setup Mode Register */
+               XM_OUT32(IoC, Port, XM_MODE, MdReg);
+       }
+#endif /* GENESIS */
+       
+#ifdef YUKON
+       if (pAC->GIni.GIYukon) {
+               
+               GM_IN16(IoC, Port, GM_RX_CTRL, &RcReg);
+               
+               /* enable or disable multicast filtering */
+               if (Enable) {
+                       RcReg |= GM_RXCR_MCF_ENA;
+               }
+               else {
+                       RcReg &= ~GM_RXCR_MCF_ENA;
+               }
+               /* setup Receive Control Register */
+               GM_OUT16(IoC, Port, GM_RX_CTRL, RcReg);
+       }
+#endif /* YUKON */
+
+}      /* SkMacHashing*/
+
+
+#ifdef SK_DIAG
+/******************************************************************************
+ *
+ *     SkXmSetRxCmd() - Modify the value of the XMAC's Rx Command Register
+ *
+ * Description:
+ *     The features
+ *      - FCS stripping,                                       SK_STRIP_FCS_ON/OFF
+ *      - pad byte stripping,                          SK_STRIP_PAD_ON/OFF
+ *      - don't set XMR_FS_ERR in status       SK_LENERR_OK_ON/OFF
+ *        for inrange length error frames
+ *      - don't set XMR_FS_ERR in status       SK_BIG_PK_OK_ON/OFF
+ *        for frames > 1514 bytes
+ *   - enable Rx of own packets         SK_SELF_RX_ON/OFF
+ *
+ *     for incoming packets may be enabled/disabled by this function.
+ *     Additional modes may be added later.
+ *     Multiple modes can be enabled/disabled at the same time.
+ *     The new configuration is written to the Rx Command register immediately.
+ *
+ * Returns:
+ *     nothing
+ */
+static void SkXmSetRxCmd(
+SK_AC  *pAC,           /* adapter context */
+SK_IOC IoC,            /* IO context */
+int            Port,           /* Port Index (MAC_1 + n) */
+int            Mode)           /* Mode is SK_STRIP_FCS_ON/OFF, SK_STRIP_PAD_ON/OFF,
+                                          SK_LENERR_OK_ON/OFF, or SK_BIG_PK_OK_ON/OFF */
+{
+       SK_U16  OldRxCmd;
+       SK_U16  RxCmd;
+
+       XM_IN16(IoC, Port, XM_RX_CMD, &OldRxCmd);
+
+       RxCmd = OldRxCmd;
+       
+       switch (Mode & (SK_STRIP_FCS_ON | SK_STRIP_FCS_OFF)) {
+       case SK_STRIP_FCS_ON:
+               RxCmd |= XM_RX_STRIP_FCS;
+               break;
+       case SK_STRIP_FCS_OFF:
+               RxCmd &= ~XM_RX_STRIP_FCS;
+               break;
+       }
+
+       switch (Mode & (SK_STRIP_PAD_ON | SK_STRIP_PAD_OFF)) {
+       case SK_STRIP_PAD_ON:
+               RxCmd |= XM_RX_STRIP_PAD;
+               break;
+       case SK_STRIP_PAD_OFF:
+               RxCmd &= ~XM_RX_STRIP_PAD;
+               break;
+       }
+
+       switch (Mode & (SK_LENERR_OK_ON | SK_LENERR_OK_OFF)) {
+       case SK_LENERR_OK_ON:
+               RxCmd |= XM_RX_LENERR_OK;
+               break;
+       case SK_LENERR_OK_OFF:
+               RxCmd &= ~XM_RX_LENERR_OK;
+               break;
+       }
+
+       switch (Mode & (SK_BIG_PK_OK_ON | SK_BIG_PK_OK_OFF)) {
+       case SK_BIG_PK_OK_ON:
+               RxCmd |= XM_RX_BIG_PK_OK;
+               break;
+       case SK_BIG_PK_OK_OFF:
+               RxCmd &= ~XM_RX_BIG_PK_OK;
+               break;
+       }
+
+       switch (Mode & (SK_SELF_RX_ON | SK_SELF_RX_OFF)) {
+       case SK_SELF_RX_ON:
+               RxCmd |= XM_RX_SELF_RX;
+               break;
+       case SK_SELF_RX_OFF:
+               RxCmd &= ~XM_RX_SELF_RX;
+               break;
+       }
+
+       /* Write the new mode to the Rx command register if required */
+       if (OldRxCmd != RxCmd) {
+               XM_OUT16(IoC, Port, XM_RX_CMD, RxCmd);
+       }
+}      /* SkXmSetRxCmd */
+
+
+/******************************************************************************
+ *
+ *     SkGmSetRxCmd() - Modify the value of the GMAC's Rx Control Register
+ *
+ * Description:
+ *     The features
+ *      - FCS (CRC) stripping,                         SK_STRIP_FCS_ON/OFF
+ *      - don't set GMR_FS_LONG_ERR            SK_BIG_PK_OK_ON/OFF
+ *        for frames > 1514 bytes
+ *   - enable Rx of own packets         SK_SELF_RX_ON/OFF
+ *
+ *     for incoming packets may be enabled/disabled by this function.
+ *     Additional modes may be added later.
+ *     Multiple modes can be enabled/disabled at the same time.
+ *     The new configuration is written to the Rx Command register immediately.
+ *
+ * Returns:
+ *     nothing
+ */
+static void SkGmSetRxCmd(
+SK_AC  *pAC,           /* adapter context */
+SK_IOC IoC,            /* IO context */
+int            Port,           /* Port Index (MAC_1 + n) */
+int            Mode)           /* Mode is SK_STRIP_FCS_ON/OFF, SK_STRIP_PAD_ON/OFF,
+                                          SK_LENERR_OK_ON/OFF, or SK_BIG_PK_OK_ON/OFF */
+{
+       SK_U16  OldRxCmd;
+       SK_U16  RxCmd;
+
+       if ((Mode & (SK_STRIP_FCS_ON | SK_STRIP_FCS_OFF)) != 0) {
+               
+               GM_IN16(IoC, Port, GM_RX_CTRL, &OldRxCmd);
+
+               RxCmd = OldRxCmd;
+
+               if ((Mode & SK_STRIP_FCS_ON) != 0) {
+                       RxCmd |= GM_RXCR_CRC_DIS;
+               }
+               else {
+                       RxCmd &= ~GM_RXCR_CRC_DIS;
+               }
+               /* Write the new mode to the Rx control register if required */
+               if (OldRxCmd != RxCmd) {
+                       GM_OUT16(IoC, Port, GM_RX_CTRL, RxCmd);
+               }
+       }
+
+       if ((Mode & (SK_BIG_PK_OK_ON | SK_BIG_PK_OK_OFF)) != 0) {
+               
+               GM_IN16(IoC, Port, GM_SERIAL_MODE, &OldRxCmd);
+
+               RxCmd = OldRxCmd;
+
+               if ((Mode & SK_BIG_PK_OK_ON) != 0) {
+                       RxCmd |= GM_SMOD_JUMBO_ENA;
+               }
+               else {
+                       RxCmd &= ~GM_SMOD_JUMBO_ENA;
+               }
+               /* Write the new mode to the Rx control register if required */
+               if (OldRxCmd != RxCmd) {
+                       GM_OUT16(IoC, Port, GM_SERIAL_MODE, RxCmd);
+               }
+       }
+}      /* SkGmSetRxCmd */
+
+
+/******************************************************************************
+ *
+ *     SkMacSetRxCmd() - Modify the value of the MAC's Rx Control Register
+ *
+ * Description:        modifies the MAC's Rx Control reg. dep. on board type
+ *
+ * Returns:
+ *     nothing
+ */
+void SkMacSetRxCmd(
+SK_AC  *pAC,           /* adapter context */
+SK_IOC IoC,            /* IO context */
+int            Port,           /* Port Index (MAC_1 + n) */
+int            Mode)           /* Rx Mode */
+{
+       if (pAC->GIni.GIGenesis) {
+               
+               SkXmSetRxCmd(pAC, IoC, Port, Mode);
+       }
+       else {
+               
+               SkGmSetRxCmd(pAC, IoC, Port, Mode);
+       }
+
+}      /* SkMacSetRxCmd */
+
+
+/******************************************************************************
+ *
+ *     SkMacCrcGener() - Enable / Disable CRC Generation
+ *
+ * Description:        enables / disables CRC generation dep. on board type
+ *
+ * Returns:
+ *     nothing
+ */
+void SkMacCrcGener(
+SK_AC  *pAC,   /* adapter context */
+SK_IOC IoC,    /* IO context */
+int            Port,   /* Port Index (MAC_1 + n) */
+SK_BOOL        Enable) /* Enable / Disable */
+{
+       SK_U16  Word;
+
+       if (pAC->GIni.GIGenesis) {
+               
+               XM_IN16(IoC, Port, XM_TX_CMD, &Word);
+
+               if (Enable) {
+                       Word &= ~XM_TX_NO_CRC;
+               }
+               else {
+                       Word |= XM_TX_NO_CRC;
+               }
+               /* setup Tx Command Register */
+               XM_OUT16(IoC, Port, XM_TX_CMD, Word);
+       }
+       else {
+               
+               GM_IN16(IoC, Port, GM_TX_CTRL, &Word);
+               
+               if (Enable) {
+                       Word &= ~GM_TXCR_CRC_DIS;
+               }
+               else {
+                       Word |= GM_TXCR_CRC_DIS;
+               }
+               /* setup Tx Control Register */
+               GM_OUT16(IoC, Port, GM_TX_CTRL, Word);
+       }
+
+}      /* SkMacCrcGener*/
+
+#endif /* SK_DIAG */
+
+
+#ifdef GENESIS
+/******************************************************************************
+ *
+ *     SkXmClrExactAddr() - Clear Exact Match Address Registers
+ *
+ * Description:
+ *     All Exact Match Address registers of the XMAC 'Port' will be
+ *     cleared starting with 'StartNum' up to (and including) the
+ *     Exact Match address number of 'StopNum'.
+ *
+ * Returns:
+ *     nothing
+ */
+void SkXmClrExactAddr(
+SK_AC  *pAC,           /* adapter context */
+SK_IOC IoC,            /* IO context */
+int            Port,           /* Port Index (MAC_1 + n) */
+int            StartNum,       /* Begin with this Address Register Index (0..15) */
+int            StopNum)        /* Stop after finished with this Register Idx (0..15) */
+{
+       int             i;
+       SK_U16  ZeroAddr[3] = {0x0000, 0x0000, 0x0000};
+
+       if ((unsigned)StartNum > 15 || (unsigned)StopNum > 15 ||
+               StartNum > StopNum) {
+
+               SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E001, SKERR_HWI_E001MSG);
+               return;
+       }
+
+       for (i = StartNum; i <= StopNum; i++) {
+               XM_OUTADDR(IoC, Port, XM_EXM(i), &ZeroAddr[0]);
+       }
+}      /* SkXmClrExactAddr */
+#endif /* GENESIS */
+
+
+/******************************************************************************
+ *
+ *     SkMacFlushTxFifo() - Flush the MAC's transmit FIFO
+ *
+ * Description:
+ *     Flush the transmit FIFO of the MAC specified by the index 'Port'
+ *
+ * Returns:
+ *     nothing
+ */
+void SkMacFlushTxFifo(
+SK_AC  *pAC,   /* adapter context */
+SK_IOC IoC,    /* IO context */
+int            Port)   /* Port Index (MAC_1 + n) */
+{
+#ifdef GENESIS
+       SK_U32  MdReg;
+
+       if (pAC->GIni.GIGenesis) {
+               
+               XM_IN32(IoC, Port, XM_MODE, &MdReg);
+
+               XM_OUT32(IoC, Port, XM_MODE, MdReg | XM_MD_FTF);
+       }
+#endif /* GENESIS */
+       
+#ifdef YUKON
+       if (pAC->GIni.GIYukon) {
+               /* no way to flush the FIFO we have to issue a reset */
+               /* TBD */
+       }
+#endif /* YUKON */
+
+}      /* SkMacFlushTxFifo */
+
+
+/******************************************************************************
+ *
+ *     SkMacFlushRxFifo() - Flush the MAC's receive FIFO
+ *
+ * Description:
+ *     Flush the receive FIFO of the MAC specified by the index 'Port'
+ *
+ * Returns:
+ *     nothing
+ */
+static void SkMacFlushRxFifo(
+SK_AC  *pAC,   /* adapter context */
+SK_IOC IoC,    /* IO context */
+int            Port)   /* Port Index (MAC_1 + n) */
+{
+#ifdef GENESIS
+       SK_U32  MdReg;
+
+       if (pAC->GIni.GIGenesis) {
+
+               XM_IN32(IoC, Port, XM_MODE, &MdReg);
+
+               XM_OUT32(IoC, Port, XM_MODE, MdReg | XM_MD_FRF);
+       }
+#endif /* GENESIS */
+       
+#ifdef YUKON
+       if (pAC->GIni.GIYukon) {
+               /* no way to flush the FIFO we have to issue a reset */
+               /* TBD */
+       }
+#endif /* YUKON */
+
+}      /* SkMacFlushRxFifo */
+
+
+#ifdef GENESIS
+/******************************************************************************
+ *
+ *     SkXmSoftRst() - Do a XMAC software reset
+ *
+ * Description:
+ *     The PHY registers should not be destroyed during this
+ *     kind of software reset. Therefore the XMAC Software Reset
+ *     (XM_GP_RES_MAC bit in XM_GP_PORT) must not be used!
+ *
+ *     The software reset is done by
+ *             - disabling the Rx and Tx state machine,
+ *             - resetting the statistics module,
+ *             - clear all other significant XMAC Mode,
+ *               Command, and Control Registers
+ *             - clearing the Hash Register and the
+ *               Exact Match Address registers, and
+ *             - flushing the XMAC's Rx and Tx FIFOs.
+ *
+ * Note:
+ *     Another requirement when stopping the XMAC is to
+ *     avoid sending corrupted frames on the network.
+ *     Disabling the Tx state machine will NOT interrupt
+ *     the currently transmitted frame. But we must take care
+ *     that the Tx FIFO is cleared AFTER the current frame
+ *     is complete sent to the network.
+ *
+ *     It takes about 12ns to send a frame with 1538 bytes.
+ *     One PCI clock goes at least 15ns (66MHz). Therefore
+ *     after reading XM_GP_PORT back, we are sure that the
+ *     transmitter is disabled AND idle. And this means
+ *     we may flush the transmit FIFO now.
+ *
+ * Returns:
+ *     nothing
+ */
+static void SkXmSoftRst(
+SK_AC  *pAC,   /* adapter context */
+SK_IOC IoC,    /* IO context */
+int            Port)   /* Port Index (MAC_1 + n) */
+{
+       SK_U16  ZeroAddr[4] = {0x0000, 0x0000, 0x0000, 0x0000};
+       
+       /* reset the statistics module */
+       XM_OUT32(IoC, Port, XM_GP_PORT, XM_GP_RES_STAT);
+
+       /* disable all XMAC IRQs */
+       XM_OUT16(IoC, Port, XM_IMSK, 0xffff);
+       
+       XM_OUT32(IoC, Port, XM_MODE, 0);                /* clear Mode Reg */
+       
+       XM_OUT16(IoC, Port, XM_TX_CMD, 0);              /* reset TX CMD Reg */
+       XM_OUT16(IoC, Port, XM_RX_CMD, 0);              /* reset RX CMD Reg */
+       
+       /* disable all PHY IRQs */
+       switch (pAC->GIni.GP[Port].PhyType) {
+       case SK_PHY_BCOM:
+                       SkXmPhyWrite(pAC, IoC, Port, PHY_BCOM_INT_MASK, 0xffff);
+                       break;
+#ifdef OTHER_PHY
+               case SK_PHY_LONE:
+                       SkXmPhyWrite(pAC, IoC, Port, PHY_LONE_INT_ENAB, 0);
+                       break;
+               case SK_PHY_NAT:
+                       /* todo: National
+                        SkXmPhyWrite(pAC, IoC, Port, PHY_NAT_INT_MASK, 0xffff); */
+                       break;
+#endif /* OTHER_PHY */
+       }
+
+       /* clear the Hash Register */
+       XM_OUTHASH(IoC, Port, XM_HSM, &ZeroAddr);
+
+       /* clear the Exact Match Address registers */
+       SkXmClrExactAddr(pAC, IoC, Port, 0, 15);
+       
+       /* clear the Source Check Address registers */
+       XM_OUTHASH(IoC, Port, XM_SRC_CHK, &ZeroAddr);
+
+}      /* SkXmSoftRst */
+
+
+/******************************************************************************
+ *
+ *     SkXmHardRst() - Do a XMAC hardware reset
+ *
+ * Description:
+ *     The XMAC of the specified 'Port' and all connected devices
+ *     (PHY and SERDES) will receive a reset signal on its *Reset pins.
+ *     External PHYs must be reset by clearing a bit in the GPIO register
+ *  (Timing requirements: Broadcom: 400ns, Level One: none, National: 80ns).
+ *
+ * ATTENTION:
+ *     It is absolutely necessary to reset the SW_RST Bit first
+ *     before calling this function.
+ *
+ * Returns:
+ *     nothing
+ */
+static void SkXmHardRst(
+SK_AC  *pAC,   /* adapter context */
+SK_IOC IoC,    /* IO context */
+int            Port)   /* Port Index (MAC_1 + n) */
+{
+       SK_U32  Reg;
+       int             i;
+       int             TOut;
+       SK_U16  Word;
+
+       for (i = 0; i < 4; i++) {
+               /* TX_MFF_CTRL1 has 32 bits, but only the lowest 16 bits are used */
+               SK_OUT16(IoC, MR_ADDR(Port, TX_MFF_CTRL1), MFF_CLR_MAC_RST);
+
+               TOut = 0;
+               do {
+                       if (TOut++ > 10000) {
+                               /*
+                                * Adapter seems to be in RESET state.
+                                * Registers cannot be written.
+                                */
+                               return;
+                       }
+
+                       SK_OUT16(IoC, MR_ADDR(Port, TX_MFF_CTRL1), MFF_SET_MAC_RST);
+                       
+                       SK_IN16(IoC, MR_ADDR(Port, TX_MFF_CTRL1), &Word);
+               
+               } while ((Word & MFF_SET_MAC_RST) == 0);
+       }
+
+       /* For external PHYs there must be special handling */
+       if (pAC->GIni.GP[Port].PhyType != SK_PHY_XMAC) {
+               
+               SK_IN32(IoC, B2_GP_IO, &Reg);
+               
+               if (Port == 0) {
+                       Reg |= GP_DIR_0;        /* set to output */
+                       Reg &= ~GP_IO_0;        /* set PHY reset (active low) */
+               }
+               else {
+                       Reg |= GP_DIR_2;        /* set to output */
+                       Reg &= ~GP_IO_2;        /* set PHY reset (active low) */
+               }
+               /* reset external PHY */
+               SK_OUT32(IoC, B2_GP_IO, Reg);
+
+               /* short delay */
+               SK_IN32(IoC, B2_GP_IO, &Reg);
+       }
+}      /* SkXmHardRst */
+
+
+/******************************************************************************
+ *
+ *     SkXmClearRst() - Release the PHY & XMAC reset
+ *
+ * Description:
+ *
+ * Returns:
+ *     nothing
+ */
+static void SkXmClearRst(
+SK_AC  *pAC,   /* adapter context */
+SK_IOC IoC,    /* IO context */
+int            Port)   /* Port Index (MAC_1 + n) */
+{
+       SK_U32  DWord;
+       
+       /* clear HW reset */
+       SK_OUT16(IoC, MR_ADDR(Port, TX_MFF_CTRL1), MFF_CLR_MAC_RST);
+
+       if (pAC->GIni.GP[Port].PhyType != SK_PHY_XMAC) {
+
+               SK_IN32(IoC, B2_GP_IO, &DWord);
+
+               if (Port == 0) {
+                       DWord |= (GP_DIR_0 | GP_IO_0); /* set to output */
+               }
+               else {
+                       DWord |= (GP_DIR_2 | GP_IO_2); /* set to output */
+               }
+               /* Clear PHY reset */
+               SK_OUT32(IoC, B2_GP_IO, DWord);
+
+               /* Enable GMII interface */
+               XM_OUT16(IoC, Port, XM_HW_CFG, XM_HW_GMII_MD);
+       }
+}      /* SkXmClearRst */
+#endif /* GENESIS */
+
+
+#ifdef YUKON
+/******************************************************************************
+ *
+ *     SkGmSoftRst() - Do a GMAC software reset
+ *
+ * Description:
+ *     The GPHY registers should not be destroyed during this
+ *     kind of software reset.
+ *
+ * Returns:
+ *     nothing
+ */
+static void SkGmSoftRst(
+SK_AC  *pAC,   /* adapter context */
+SK_IOC IoC,    /* IO context */
+int            Port)   /* Port Index (MAC_1 + n) */
+{
+       SK_U16  EmptyHash[4] = {0x0000, 0x0000, 0x0000, 0x0000};
+       SK_U16  RxCtrl;
+
+       /* reset the statistics module */
+
+       /* disable all GMAC IRQs */
+       SK_OUT8(IoC, GMAC_IRQ_MSK, 0);
+       
+       /* disable all PHY IRQs */
+       SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_INT_MASK, 0);
+       
+       /* clear the Hash Register */
+       GM_OUTHASH(IoC, Port, GM_MC_ADDR_H1, EmptyHash);
+
+       /* Enable Unicast and Multicast filtering */
+       GM_IN16(IoC, Port, GM_RX_CTRL, &RxCtrl);
+       
+       GM_OUT16(IoC, Port, GM_RX_CTRL,
+               (SK_U16)(RxCtrl | GM_RXCR_UCF_ENA | GM_RXCR_MCF_ENA));
+
+}      /* SkGmSoftRst */
+
+
+/******************************************************************************
+ *
+ *     SkGmHardRst() - Do a GMAC hardware reset
+ *
+ * Description:
+ *
+ * Returns:
+ *     nothing
+ */
+static void SkGmHardRst(
+SK_AC  *pAC,   /* adapter context */
+SK_IOC IoC,    /* IO context */
+int            Port)   /* Port Index (MAC_1 + n) */
+{
+       SK_U32  DWord;
+       
+       /* WA code for COMA mode */
+       if (pAC->GIni.GIYukonLite &&
+               pAC->GIni.GIChipRev >= CHIP_REV_YU_LITE_A3) {
+               
+               SK_IN32(IoC, B2_GP_IO, &DWord);
+
+               DWord |= (GP_DIR_9 | GP_IO_9);
+
+               /* set PHY reset */
+               SK_OUT32(IoC, B2_GP_IO, DWord);
+       }
+
+       /* set GPHY Control reset */
+       SK_OUT32(IoC, MR_ADDR(Port, GPHY_CTRL), GPC_RST_SET);
+
+       /* set GMAC Control reset */
+       SK_OUT32(IoC, MR_ADDR(Port, GMAC_CTRL), GMC_RST_SET);
+
+}      /* SkGmHardRst */
+
+
+/******************************************************************************
+ *
+ *     SkGmClearRst() - Release the GPHY & GMAC reset
+ *
+ * Description:
+ *
+ * Returns:
+ *     nothing
+ */
+static void SkGmClearRst(
+SK_AC  *pAC,   /* adapter context */
+SK_IOC IoC,    /* IO context */
+int            Port)   /* Port Index (MAC_1 + n) */
+{
+       SK_U32  DWord;
+       
+#ifdef XXX
+               /* clear GMAC Control reset */
+               SK_OUT32(IoC, MR_ADDR(Port, GMAC_CTRL), GMC_RST_CLR);
+
+               /* set GMAC Control reset */
+               SK_OUT32(IoC, MR_ADDR(Port, GMAC_CTRL), GMC_RST_SET);
+#endif /* XXX */
+
+       /* WA code for COMA mode */
+       if (pAC->GIni.GIYukonLite &&
+               pAC->GIni.GIChipRev >= CHIP_REV_YU_LITE_A3) {
+               
+               SK_IN32(IoC, B2_GP_IO, &DWord);
+
+               DWord |= GP_DIR_9;              /* set to output */
+               DWord &= ~GP_IO_9;              /* clear PHY reset (active high) */
+
+               /* clear PHY reset */
+               SK_OUT32(IoC, B2_GP_IO, DWord);
+       }
+
+       /* set HWCFG_MODE */
+       DWord = GPC_INT_POL_HI | GPC_DIS_FC | GPC_DIS_SLEEP |
+               GPC_ENA_XC | GPC_ANEG_ADV_ALL_M | GPC_ENA_PAUSE |
+               (pAC->GIni.GICopperType ? GPC_HWCFG_GMII_COP :
+               GPC_HWCFG_GMII_FIB);
+
+       /* set GPHY Control reset */
+       SK_OUT32(IoC, MR_ADDR(Port, GPHY_CTRL), DWord | GPC_RST_SET);
+
+       /* release GPHY Control reset */
+       SK_OUT32(IoC, MR_ADDR(Port, GPHY_CTRL), DWord | GPC_RST_CLR);
+
+#ifdef VCPU
+       VCpuWait(9000);
+#endif /* VCPU */
+
+       /* clear GMAC Control reset */
+       SK_OUT32(IoC, MR_ADDR(Port, GMAC_CTRL), GMC_PAUSE_ON | GMC_RST_CLR);
+
+#ifdef VCPU
+       VCpuWait(2000);
+       
+       SK_IN32(IoC, MR_ADDR(Port, GPHY_CTRL), &DWord);
+                       
+       SK_IN32(IoC, B0_ISRC, &DWord);
+#endif /* VCPU */
+
+}      /* SkGmClearRst */
+#endif /* YUKON */
+
+
+/******************************************************************************
+ *
+ *     SkMacSoftRst() - Do a MAC software reset
+ *
+ * Description:        calls a MAC software reset routine dep. on board type
+ *
+ * Returns:
+ *     nothing
+ */
+void SkMacSoftRst(
+SK_AC  *pAC,   /* adapter context */
+SK_IOC IoC,    /* IO context */
+int            Port)   /* Port Index (MAC_1 + n) */
+{
+       SK_GEPORT       *pPrt;
+
+       pPrt = &pAC->GIni.GP[Port];
+
+       /* disable receiver and transmitter */
+       SkMacRxTxDisable(pAC, IoC, Port);
+
+#ifdef GENESIS
+       if (pAC->GIni.GIGenesis) {
+               
+               SkXmSoftRst(pAC, IoC, Port);
+       }
+#endif /* GENESIS */
+       
+#ifdef YUKON
+       if (pAC->GIni.GIYukon) {
+               
+               SkGmSoftRst(pAC, IoC, Port);
+       }
+#endif /* YUKON */
+
+       /* flush the MAC's Rx and Tx FIFOs */
+       SkMacFlushTxFifo(pAC, IoC, Port);
+       
+       SkMacFlushRxFifo(pAC, IoC, Port);
+
+       pPrt->PState = SK_PRT_STOP;
+
+}      /* SkMacSoftRst */
+
+
+/******************************************************************************
+ *
+ *     SkMacHardRst() - Do a MAC hardware reset
+ *
+ * Description:        calls a MAC hardware reset routine dep. on board type
+ *
+ * Returns:
+ *     nothing
+ */
+void SkMacHardRst(
+SK_AC  *pAC,   /* adapter context */
+SK_IOC IoC,    /* IO context */
+int            Port)   /* Port Index (MAC_1 + n) */
+{
+       
+#ifdef GENESIS
+       if (pAC->GIni.GIGenesis) {
+               
+               SkXmHardRst(pAC, IoC, Port);
+       }
+#endif /* GENESIS */
+       
+#ifdef YUKON
+       if (pAC->GIni.GIYukon) {
+               
+               SkGmHardRst(pAC, IoC, Port);
+       }
+#endif /* YUKON */
+
+       pAC->GIni.GP[Port].PState = SK_PRT_RESET;
+
+}      /* SkMacHardRst */
+
+
+#ifdef GENESIS
+/******************************************************************************
+ *
+ *     SkXmInitMac() - Initialize the XMAC II
+ *
+ * Description:
+ *     Initialize the XMAC of the specified port.
+ *     The XMAC must be reset or stopped before calling this function.
+ *
+ * Note:
+ *     The XMAC's Rx and Tx state machine is still disabled when returning.
+ *
+ * Returns:
+ *     nothing
+ */
+void SkXmInitMac(
+SK_AC  *pAC,           /* adapter context */
+SK_IOC IoC,            /* IO context */
+int            Port)           /* Port Index (MAC_1 + n) */
+{
+       SK_GEPORT       *pPrt;
+       int                     i;
+       SK_U16          SWord;
+
+       pPrt = &pAC->GIni.GP[Port];
+
+       if (pPrt->PState == SK_PRT_STOP) {
+               /* Port State: SK_PRT_STOP */
+               /* Verify that the reset bit is cleared */
+               SK_IN16(IoC, MR_ADDR(Port, TX_MFF_CTRL1), &SWord);
+
+               if ((SWord & MFF_SET_MAC_RST) != 0) {
+                       /* PState does not match HW state */
+                       SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E006, SKERR_HWI_E006MSG);
+                       /* Correct it */
+                       pPrt->PState = SK_PRT_RESET;
+               }
+       }
+
+       if (pPrt->PState == SK_PRT_RESET) {
+
+               SkXmClearRst(pAC, IoC, Port);
+
+               if (pPrt->PhyType != SK_PHY_XMAC) {
+                       /* read Id from external PHY (all have the same address) */
+                       SkXmPhyRead(pAC, IoC, Port, PHY_XMAC_ID1, &pPrt->PhyId1);
+
+                       /*
+                        * Optimize MDIO transfer by suppressing preamble.
+                        * Must be done AFTER first access to BCOM chip.
+                        */
+                       XM_IN16(IoC, Port, XM_MMU_CMD, &SWord);
+                       
+                       XM_OUT16(IoC, Port, XM_MMU_CMD, SWord | XM_MMU_NO_PRE);
+
+                       if (pPrt->PhyId1 == PHY_BCOM_ID1_C0) {
+                               /*
+                                * Workaround BCOM Errata for the C0 type.
+                                * Write magic patterns to reserved registers.
+                                */
+                               i = 0;
+                               while (BcomRegC0Hack[i].PhyReg != 0) {
+                                       SkXmPhyWrite(pAC, IoC, Port, BcomRegC0Hack[i].PhyReg,
+                                               BcomRegC0Hack[i].PhyVal);
+                                       i++;
+                               }
+                       }
+                       else if (pPrt->PhyId1 == PHY_BCOM_ID1_A1) {
+                               /*
+                                * Workaround BCOM Errata for the A1 type.
+                                * Write magic patterns to reserved registers.
+                                */
+                               i = 0;
+                               while (BcomRegA1Hack[i].PhyReg != 0) {
+                                       SkXmPhyWrite(pAC, IoC, Port, BcomRegA1Hack[i].PhyReg,
+                                               BcomRegA1Hack[i].PhyVal);
+                                       i++;
+                               }
+                       }
+
+                       /*
+                        * Workaround BCOM Errata (#10523) for all BCom PHYs.
+                        * Disable Power Management after reset.
+                        */
+                       SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_AUX_CTRL, &SWord);
+                       
+                       SkXmPhyWrite(pAC, IoC, Port, PHY_BCOM_AUX_CTRL,
+                               (SK_U16)(SWord | PHY_B_AC_DIS_PM));
+
+                       /* PHY LED initialization is done in SkGeXmitLED() */
+               }
+
+               /* Dummy read the Interrupt source register */
+               XM_IN16(IoC, Port, XM_ISRC, &SWord);
+               
+               /*
+                * The auto-negotiation process starts immediately after
+                * clearing the reset. The auto-negotiation process should be
+                * started by the SIRQ, therefore stop it here immediately.
+                */
+               SkMacInitPhy(pAC, IoC, Port, SK_FALSE);
+
+#ifdef TEST_ONLY
+               /* temp. code: enable signal detect */
+               /* WARNING: do not override GMII setting above */
+               XM_OUT16(IoC, Port, XM_HW_CFG, XM_HW_COM4SIG);
+#endif
+       }
+
+       /*
+        * configure the XMACs Station Address
+        * B2_MAC_2 = xx xx xx xx xx x1 is programmed to XMAC A
+        * B2_MAC_3 = xx xx xx xx xx x2 is programmed to XMAC B
+        */
+       for (i = 0; i < 3; i++) {
+               /*
+                * The following 2 statements are together endianess
+                * independent. Remember this when changing.
+                */
+               SK_IN16(IoC, (B2_MAC_2 + Port * 8 + i * 2), &SWord);
+               
+               XM_OUT16(IoC, Port, (XM_SA + i * 2), SWord);
+       }
+
+       /* Tx Inter Packet Gap (XM_TX_IPG):     use default */
+       /* Tx High Water Mark (XM_TX_HI_WM):    use default */
+       /* Tx Low Water Mark (XM_TX_LO_WM):     use default */
+       /* Host Request Threshold (XM_HT_THR):  use default */
+       /* Rx Request Threshold (XM_RX_THR):    use default */
+       /* Rx Low Water Mark (XM_RX_LO_WM):     use default */
+
+       /* configure Rx High Water Mark (XM_RX_HI_WM) */
+       XM_OUT16(IoC, Port, XM_RX_HI_WM, SK_XM_RX_HI_WM);
+
+       /* Configure Tx Request Threshold */
+       SWord = SK_XM_THR_SL;                           /* for single port */
+
+       if (pAC->GIni.GIMacsFound > 1) {
+               switch (pAC->GIni.GIPortUsage) {
+               case SK_RED_LINK:
+                       SWord = SK_XM_THR_REDL;         /* redundant link */
+                       break;
+               case SK_MUL_LINK:
+                       SWord = SK_XM_THR_MULL;         /* load balancing */
+                       break;
+               case SK_JUMBO_LINK:
+                       SWord = SK_XM_THR_JUMBO;        /* jumbo frames */
+                       break;
+               default:
+                       SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E014, SKERR_HWI_E014MSG);
+                       break;
+               }
+       }
+       XM_OUT16(IoC, Port, XM_TX_THR, SWord);
+
+       /* setup register defaults for the Tx Command Register */
+       XM_OUT16(IoC, Port, XM_TX_CMD, XM_TX_AUTO_PAD);
+
+       /* setup register defaults for the Rx Command Register */
+       SWord = XM_RX_STRIP_FCS | XM_RX_LENERR_OK;
+
+       if (pAC->GIni.GIPortUsage == SK_JUMBO_LINK) {
+               SWord |= XM_RX_BIG_PK_OK;
+       }
+
+       if (pPrt->PLinkMode == SK_LMODE_HALF) {
+               /*
+                * If in manual half duplex mode the other side might be in
+                * full duplex mode, so ignore if a carrier extension is not seen
+                * on frames received
+                */
+               SWord |= XM_RX_DIS_CEXT;
+       }
+       
+       XM_OUT16(IoC, Port, XM_RX_CMD, SWord);
+
+       /*
+        * setup register defaults for the Mode Register
+        *      - Don't strip error frames to avoid Store & Forward
+        *        on the Rx side.
+        *      - Enable 'Check Station Address' bit
+        *      - Enable 'Check Address Array' bit
+        */
+       XM_OUT32(IoC, Port, XM_MODE, XM_DEF_MODE);
+
+       /*
+        * Initialize the Receive Counter Event Mask (XM_RX_EV_MSK)
+        *      - Enable all bits excepting 'Octets Rx OK Low CntOv'
+        *        and 'Octets Rx OK Hi Cnt Ov'.
+        */
+       XM_OUT32(IoC, Port, XM_RX_EV_MSK, XMR_DEF_MSK);
+
+       /*
+        * Initialize the Transmit Counter Event Mask (XM_TX_EV_MSK)
+        *      - Enable all bits excepting 'Octets Tx OK Low CntOv'
+        *        and 'Octets Tx OK Hi Cnt Ov'.
+        */
+       XM_OUT32(IoC, Port, XM_TX_EV_MSK, XMT_DEF_MSK);
+
+       /*
+        * Do NOT init XMAC interrupt mask here.
+        * All interrupts remain disable until link comes up!
+        */
+
+       /*
+        * Any additional configuration changes may be done now.
+        * The last action is to enable the Rx and Tx state machine.
+        * This should be done after the auto-negotiation process
+        * has been completed successfully.
+        */
+}      /* SkXmInitMac */
+#endif /* GENESIS */
+
+
+#ifdef YUKON
+/******************************************************************************
+ *
+ *     SkGmInitMac() - Initialize the GMAC
+ *
+ * Description:
+ *     Initialize the GMAC of the specified port.
+ *     The GMAC must be reset or stopped before calling this function.
+ *
+ * Note:
+ *     The GMAC's Rx and Tx state machine is still disabled when returning.
+ *
+ * Returns:
+ *     nothing
+ */
+void SkGmInitMac(
+SK_AC  *pAC,           /* adapter context */
+SK_IOC IoC,            /* IO context */
+int            Port)           /* Port Index (MAC_1 + n) */
+{
+       SK_GEPORT       *pPrt;
+       int                     i;
+       SK_U16          SWord;
+       SK_U32          DWord;
+
+       pPrt = &pAC->GIni.GP[Port];
+
+       if (pPrt->PState == SK_PRT_STOP) {
+               /* Port State: SK_PRT_STOP */
+               /* Verify that the reset bit is cleared */
+               SK_IN32(IoC, MR_ADDR(Port, GMAC_CTRL), &DWord);
+               
+               if ((DWord & GMC_RST_SET) != 0) {
+                       /* PState does not match HW state */
+                       SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E006, SKERR_HWI_E006MSG);
+                       /* Correct it */
+                       pPrt->PState = SK_PRT_RESET;
+               }
+       }
+
+       if (pPrt->PState == SK_PRT_RESET) {
+               
+               SkGmHardRst(pAC, IoC, Port);
+
+               SkGmClearRst(pAC, IoC, Port);
+               
+               /* Auto-negotiation ? */
+               if (pPrt->PLinkMode == SK_LMODE_HALF || pPrt->PLinkMode == SK_LMODE_FULL) {
+                       /* Auto-negotiation disabled */
+
+                       /* get General Purpose Control */
+                       GM_IN16(IoC, Port, GM_GP_CTRL, &SWord);
+
+                       /* disable auto-update for speed, duplex and flow-control */
+                       SWord |= GM_GPCR_AU_ALL_DIS;
+                       
+                       /* setup General Purpose Control Register */
+                       GM_OUT16(IoC, Port, GM_GP_CTRL, SWord);
+                       
+                       SWord = GM_GPCR_AU_ALL_DIS;
+               }
+               else {
+                       SWord = 0;
+               }
+
+               /* speed settings */
+               switch (pPrt->PLinkSpeed) {
+               case SK_LSPEED_AUTO:
+               case SK_LSPEED_1000MBPS:
+                       SWord |= GM_GPCR_SPEED_1000 | GM_GPCR_SPEED_100;
+                       break;
+               case SK_LSPEED_100MBPS:
+                       SWord |= GM_GPCR_SPEED_100;
+                       break;
+               case SK_LSPEED_10MBPS:
+                       break;
+               }
+
+               /* duplex settings */
+               if (pPrt->PLinkMode != SK_LMODE_HALF) {
+                       /* set full duplex */
+                       SWord |= GM_GPCR_DUP_FULL;
+               }
+
+               /* flow-control settings */
+               switch (pPrt->PFlowCtrlMode) {
+               case SK_FLOW_MODE_NONE:
+                       /* set Pause Off */
+                       SK_OUT32(IoC, MR_ADDR(Port, GMAC_CTRL), GMC_PAUSE_OFF);
+                       /* disable Tx & Rx flow-control */
+                       SWord |= GM_GPCR_FC_TX_DIS | GM_GPCR_FC_RX_DIS | GM_GPCR_AU_FCT_DIS;
+                       break;
+               case SK_FLOW_MODE_LOC_SEND:
+                       /* disable Rx flow-control */
+                       SWord |= GM_GPCR_FC_RX_DIS | GM_GPCR_AU_FCT_DIS;
+                       break;
+               case SK_FLOW_MODE_SYMMETRIC:
+               case SK_FLOW_MODE_SYM_OR_REM:
+                       /* enable Tx & Rx flow-control */
+                       break;
+               }
+
+               /* setup General Purpose Control Register */
+               GM_OUT16(IoC, Port, GM_GP_CTRL, SWord);
+
+               /* dummy read the Interrupt Source Register */
+               SK_IN16(IoC, GMAC_IRQ_SRC, &SWord);
+               
+#ifndef VCPU
+               /* read Id from PHY */
+               SkGmPhyRead(pAC, IoC, Port, PHY_MARV_ID1, &pPrt->PhyId1);
+               
+               SkGmInitPhyMarv(pAC, IoC, Port, SK_FALSE);
+#endif /* VCPU */
+       }
+
+       (void)SkGmResetCounter(pAC, IoC, Port);
+
+       /* setup Transmit Control Register */
+       GM_OUT16(IoC, Port, GM_TX_CTRL, TX_COL_THR(pPrt->PMacColThres));
+
+       /* setup Receive Control Register */
+       GM_OUT16(IoC, Port, GM_RX_CTRL, GM_RXCR_UCF_ENA | GM_RXCR_MCF_ENA |
+               GM_RXCR_CRC_DIS);
+
+       /* setup Transmit Flow Control Register */
+       GM_OUT16(IoC, Port, GM_TX_FLOW_CTRL, 0xffff);
+
+       /* setup Transmit Parameter Register */
+#ifdef VCPU
+       GM_IN16(IoC, Port, GM_TX_PARAM, &SWord);
+#endif /* VCPU */
+
+    SWord = TX_JAM_LEN_VAL(pPrt->PMacJamLen) |
+                       TX_JAM_IPG_VAL(pPrt->PMacJamIpgVal) |
+                       TX_IPG_JAM_DATA(pPrt->PMacJamIpgData);
+       
+       GM_OUT16(IoC, Port, GM_TX_PARAM, SWord);
+
+       /* configure the Serial Mode Register */
+#ifdef VCPU
+       GM_IN16(IoC, Port, GM_SERIAL_MODE, &SWord);
+#endif /* VCPU */
+       
+       SWord = GM_SMOD_VLAN_ENA | IPG_DATA_VAL(pPrt->PMacIpgData);
+
+       if (pPrt->PMacLimit4) {
+               /* reset of collision counter after 4 consecutive collisions */
+               SWord |= GM_SMOD_LIMIT_4;
+       }
+
+       if (pAC->GIni.GIPortUsage == SK_JUMBO_LINK) {
+               /* enable jumbo mode (Max. Frame Length = 9018) */
+               SWord |= GM_SMOD_JUMBO_ENA;
+       }
+       
+       GM_OUT16(IoC, Port, GM_SERIAL_MODE, SWord);
+       
+       /*
+        * configure the GMACs Station Addresses
+        * in PROM you can find our addresses at:
+        * B2_MAC_1 = xx xx xx xx xx x0 virtual address
+        * B2_MAC_2 = xx xx xx xx xx x1 is programmed to GMAC A
+        * B2_MAC_3 = xx xx xx xx xx x2 is reserved for DualPort
+        */
+
+       for (i = 0; i < 3; i++) {
+               /*
+                * The following 2 statements are together endianess
+                * independent. Remember this when changing.
+                */
+               /* physical address: will be used for pause frames */
+               SK_IN16(IoC, (B2_MAC_2 + Port * 8 + i * 2), &SWord);
+
+#ifdef WA_DEV_16
+               /* WA for deviation #16 */
+               if (pAC->GIni.GIChipId == CHIP_ID_YUKON && pAC->GIni.GIChipRev == 0) {
+                       /* swap the address bytes */
+                       SWord = ((SWord & 0xff00) >> 8) | ((SWord & 0x00ff) << 8);
+
+                       /* write to register in reversed order */
+                       GM_OUT16(IoC, Port, (GM_SRC_ADDR_1L + (2 - i) * 4), SWord);
+               }
+               else {
+                       GM_OUT16(IoC, Port, (GM_SRC_ADDR_1L + i * 4), SWord);
+               }
+#else          
+               GM_OUT16(IoC, Port, (GM_SRC_ADDR_1L + i * 4), SWord);
+#endif /* WA_DEV_16 */
+               
+               /* virtual address: will be used for data */
+               SK_IN16(IoC, (B2_MAC_1 + Port * 8 + i * 2), &SWord);
+
+               GM_OUT16(IoC, Port, (GM_SRC_ADDR_2L + i * 4), SWord);
+               
+               /* reset Multicast filtering Hash registers 1-3 */
+               GM_OUT16(IoC, Port, GM_MC_ADDR_H1 + 4*i, 0);
+       }
+
+       /* reset Multicast filtering Hash register 4 */
+       GM_OUT16(IoC, Port, GM_MC_ADDR_H4, 0);
+
+       /* enable interrupt mask for counter overflows */
+       GM_OUT16(IoC, Port, GM_TX_IRQ_MSK, 0);
+       GM_OUT16(IoC, Port, GM_RX_IRQ_MSK, 0);
+       GM_OUT16(IoC, Port, GM_TR_IRQ_MSK, 0);
+
+#if defined(SK_DIAG) || defined(DEBUG)
+       /* read General Purpose Status */
+       GM_IN16(IoC, Port, GM_GP_STAT, &SWord);
+       
+       SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+               ("MAC Stat Reg.=0x%04X\n", SWord));
+#endif /* SK_DIAG || DEBUG */
+
+#ifdef SK_DIAG
+       c_print("MAC Stat Reg=0x%04X\n", SWord);
+#endif /* SK_DIAG */
+
+}      /* SkGmInitMac */
+#endif /* YUKON */
+
+
+#ifdef GENESIS
+/******************************************************************************
+ *
+ *     SkXmInitDupMd() - Initialize the XMACs Duplex Mode
+ *
+ * Description:
+ *     This function initializes the XMACs Duplex Mode.
+ *     It should be called after successfully finishing
+ *     the Auto-negotiation Process
+ *
+ * Returns:
+ *     nothing
+ */
+static void SkXmInitDupMd(
+SK_AC  *pAC,           /* adapter context */
+SK_IOC IoC,            /* IO context */
+int            Port)           /* Port Index (MAC_1 + n) */
+{
+       switch (pAC->GIni.GP[Port].PLinkModeStatus) {
+       case SK_LMODE_STAT_AUTOHALF:
+       case SK_LMODE_STAT_HALF:
+               /* Configuration Actions for Half Duplex Mode */
+               /*
+                * XM_BURST = default value. We are probable not quick
+                *      enough at the 'XMAC' bus to burst 8kB.
+                *      The XMAC stops bursting if no transmit frames
+                *      are available or the burst limit is exceeded.
+                */
+               /* XM_TX_RT_LIM = default value (15) */
+               /* XM_TX_STIME = default value (0xff = 4096 bit times) */
+               break;
+       case SK_LMODE_STAT_AUTOFULL:
+       case SK_LMODE_STAT_FULL:
+               /* Configuration Actions for Full Duplex Mode */
+               /*
+                * The duplex mode is configured by the PHY,
+                * therefore it seems to be that there is nothing
+                * to do here.
+                */
+               break;
+       case SK_LMODE_STAT_UNKNOWN:
+       default:
+               SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E007, SKERR_HWI_E007MSG);
+               break;
+       }
+}      /* SkXmInitDupMd */
+
+
+/******************************************************************************
+ *
+ *     SkXmInitPauseMd() - initialize the Pause Mode to be used for this port
+ *
+ * Description:
+ *     This function initializes the Pause Mode which should
+ *     be used for this port.
+ *     It should be called after successfully finishing
+ *     the Auto-negotiation Process
+ *
+ * Returns:
+ *     nothing
+ */
+static void SkXmInitPauseMd(
+SK_AC  *pAC,           /* adapter context */
+SK_IOC IoC,            /* IO context */
+int            Port)           /* Port Index (MAC_1 + n) */
+{
+       SK_GEPORT       *pPrt;
+       SK_U32          DWord;
+       SK_U16          Word;
+
+       pPrt = &pAC->GIni.GP[Port];
+
+       XM_IN16(IoC, Port, XM_MMU_CMD, &Word);
+       
+       if (pPrt->PFlowCtrlStatus == SK_FLOW_STAT_NONE ||
+               pPrt->PFlowCtrlStatus == SK_FLOW_STAT_LOC_SEND) {
+
+               /* Disable Pause Frame Reception */
+               Word |= XM_MMU_IGN_PF;
+       }
+       else {
+               /*
+                * enabling pause frame reception is required for 1000BT
+                * because the XMAC is not reset if the link is going down
+                */
+               /* Enable Pause Frame Reception */
+               Word &= ~XM_MMU_IGN_PF;
+       }       
+       
+       XM_OUT16(IoC, Port, XM_MMU_CMD, Word);
+
+       XM_IN32(IoC, Port, XM_MODE, &DWord);
+
+       if (pPrt->PFlowCtrlStatus == SK_FLOW_STAT_SYMMETRIC ||
+               pPrt->PFlowCtrlStatus == SK_FLOW_STAT_LOC_SEND) {
+
+               /*
+                * Configure Pause Frame Generation
+                * Use internal and external Pause Frame Generation.
+                * Sending pause frames is edge triggered.
+                * Send a Pause frame with the maximum pause time if
+                * internal oder external FIFO full condition occurs.
+                * Send a zero pause time frame to re-start transmission.
+                */
+
+               /* XM_PAUSE_DA = '010000C28001' (default) */
+
+               /* XM_MAC_PTIME = 0xffff (maximum) */
+               /* remember this value is defined in big endian (!) */
+               XM_OUT16(IoC, Port, XM_MAC_PTIME, 0xffff);
+
+               /* Set Pause Mode in Mode Register */
+               DWord |= XM_PAUSE_MODE;
+
+               /* Set Pause Mode in MAC Rx FIFO */
+               SK_OUT16(IoC, MR_ADDR(Port, RX_MFF_CTRL1), MFF_ENA_PAUSE);
+       }
+       else {
+               /*
+                * disable pause frame generation is required for 1000BT
+                * because the XMAC is not reset if the link is going down
+                */
+               /* Disable Pause Mode in Mode Register */
+               DWord &= ~XM_PAUSE_MODE;
+
+               /* Disable Pause Mode in MAC Rx FIFO */
+               SK_OUT16(IoC, MR_ADDR(Port, RX_MFF_CTRL1), MFF_DIS_PAUSE);
+       }
+       
+       XM_OUT32(IoC, Port, XM_MODE, DWord);
+}      /* SkXmInitPauseMd*/
+
+
+/******************************************************************************
+ *
+ *     SkXmInitPhyXmac() - Initialize the XMAC Phy registers
+ *
+ * Description:        initializes all the XMACs Phy registers
+ *
+ * Note:
+ *
+ * Returns:
+ *     nothing
+ */
+static void SkXmInitPhyXmac(
+SK_AC  *pAC,           /* adapter context */
+SK_IOC IoC,            /* IO context */
+int            Port,           /* Port Index (MAC_1 + n) */
+SK_BOOL        DoLoop)         /* Should a Phy LoopBack be set-up? */
+{
+       SK_GEPORT       *pPrt;
+       SK_U16          Ctrl;
+
+       pPrt = &pAC->GIni.GP[Port];
+       Ctrl = 0;
+       
+       /* Auto-negotiation ? */
+       if (pPrt->PLinkMode == SK_LMODE_HALF || pPrt->PLinkMode == SK_LMODE_FULL) {
+               SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+                       ("InitPhyXmac: no auto-negotiation Port %d\n", Port));
+               /* Set DuplexMode in Config register */
+               if (pPrt->PLinkMode == SK_LMODE_FULL) {
+                       Ctrl |= PHY_CT_DUP_MD;
+               }
+
+               /*
+                * Do NOT enable Auto-negotiation here. This would hold
+                * the link down because no IDLEs are transmitted
+                */
+       }
+       else {
+               SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+                       ("InitPhyXmac: with auto-negotiation Port %d\n", Port));
+               /* Set Auto-negotiation advertisement */
+
+               /* Set Full/half duplex capabilities */
+               switch (pPrt->PLinkMode) {
+               case SK_LMODE_AUTOHALF:
+                       Ctrl |= PHY_X_AN_HD;
+                       break;
+               case SK_LMODE_AUTOFULL:
+                       Ctrl |= PHY_X_AN_FD;
+                       break;
+               case SK_LMODE_AUTOBOTH:
+                       Ctrl |= PHY_X_AN_FD | PHY_X_AN_HD;
+                       break;
+               default:
+                       SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_HWI_E015,
+                               SKERR_HWI_E015MSG);
+               }
+
+               /* Set Flow-control capabilities */
+               switch (pPrt->PFlowCtrlMode) {
+               case SK_FLOW_MODE_NONE:
+                       Ctrl |= PHY_X_P_NO_PAUSE;
+                       break;
+               case SK_FLOW_MODE_LOC_SEND:
+                       Ctrl |= PHY_X_P_ASYM_MD;
+                       break;
+               case SK_FLOW_MODE_SYMMETRIC:
+                       Ctrl |= PHY_X_P_SYM_MD;
+                       break;
+               case SK_FLOW_MODE_SYM_OR_REM:
+                       Ctrl |= PHY_X_P_BOTH_MD;
+                       break;
+               default:
+                       SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_HWI_E016,
+                               SKERR_HWI_E016MSG);
+               }
+
+               /* Write AutoNeg Advertisement Register */
+               SkXmPhyWrite(pAC, IoC, Port, PHY_XMAC_AUNE_ADV, Ctrl);
+
+               /* Restart Auto-negotiation */
+               Ctrl = PHY_CT_ANE | PHY_CT_RE_CFG;
+       }
+
+       if (DoLoop) {
+               /* Set the Phy Loopback bit, too */
+               Ctrl |= PHY_CT_LOOP;
+       }
+
+       /* Write to the Phy control register */
+       SkXmPhyWrite(pAC, IoC, Port, PHY_XMAC_CTRL, Ctrl);
+}      /* SkXmInitPhyXmac */
+
+
+/******************************************************************************
+ *
+ *     SkXmInitPhyBcom() - Initialize the Broadcom Phy registers
+ *
+ * Description:        initializes all the Broadcom Phy registers
+ *
+ * Note:
+ *
+ * Returns:
+ *     nothing
+ */
+static void SkXmInitPhyBcom(
+SK_AC  *pAC,           /* adapter context */
+SK_IOC IoC,            /* IO context */
+int            Port,           /* Port Index (MAC_1 + n) */
+SK_BOOL        DoLoop)         /* Should a Phy LoopBack be set-up? */
+{
+       SK_GEPORT       *pPrt;
+       SK_U16          Ctrl1;
+       SK_U16          Ctrl2;
+       SK_U16          Ctrl3;
+       SK_U16          Ctrl4;
+       SK_U16          Ctrl5;
+
+       Ctrl1 = PHY_CT_SP1000;
+       Ctrl2 = 0;
+       Ctrl3 = PHY_SEL_TYPE;
+       Ctrl4 = PHY_B_PEC_EN_LTR;
+       Ctrl5 = PHY_B_AC_TX_TST;
+
+       pPrt = &pAC->GIni.GP[Port];
+
+       /* manually Master/Slave ? */
+       if (pPrt->PMSMode != SK_MS_MODE_AUTO) {
+               Ctrl2 |= PHY_B_1000C_MSE;
+               
+               if (pPrt->PMSMode == SK_MS_MODE_MASTER) {
+                       Ctrl2 |= PHY_B_1000C_MSC;
+               }
+       }
+       /* Auto-negotiation ? */
+       if (pPrt->PLinkMode == SK_LMODE_HALF || pPrt->PLinkMode == SK_LMODE_FULL) {
+               SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+                       ("InitPhyBcom: no auto-negotiation Port %d\n", Port));
+               /* Set DuplexMode in Config register */
+               if (pPrt->PLinkMode == SK_LMODE_FULL) {
+                       Ctrl1 |= PHY_CT_DUP_MD;
+               }
+
+               /* Determine Master/Slave manually if not already done */
+               if (pPrt->PMSMode == SK_MS_MODE_AUTO) {
+                       Ctrl2 |= PHY_B_1000C_MSE;       /* set it to Slave */
+               }
+
+               /*
+                * Do NOT enable Auto-negotiation here. This would hold
+                * the link down because no IDLES are transmitted
+                */
+       }
+       else {
+               SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+                       ("InitPhyBcom: with auto-negotiation Port %d\n", Port));
+               /* Set Auto-negotiation advertisement */
+
+               /*
+                * Workaround BCOM Errata #1 for the C5 type.
+                * 1000Base-T Link Acquisition Failure in Slave Mode
+                * Set Repeater/DTE bit 10 of the 1000Base-T Control Register
+                */
+               Ctrl2 |= PHY_B_1000C_RD;
+               
+                /* Set Full/half duplex capabilities */
+               switch (pPrt->PLinkMode) {
+               case SK_LMODE_AUTOHALF:
+                       Ctrl2 |= PHY_B_1000C_AHD;
+                       break;
+               case SK_LMODE_AUTOFULL:
+                       Ctrl2 |= PHY_B_1000C_AFD;
+                       break;
+               case SK_LMODE_AUTOBOTH:
+                       Ctrl2 |= PHY_B_1000C_AFD | PHY_B_1000C_AHD;
+                       break;
+               default:
+                       SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_HWI_E015,
+                               SKERR_HWI_E015MSG);
+               }
+
+               /* Set Flow-control capabilities */
+               switch (pPrt->PFlowCtrlMode) {
+               case SK_FLOW_MODE_NONE:
+                       Ctrl3 |= PHY_B_P_NO_PAUSE;
+                       break;
+               case SK_FLOW_MODE_LOC_SEND:
+                       Ctrl3 |= PHY_B_P_ASYM_MD;
+                       break;
+               case SK_FLOW_MODE_SYMMETRIC:
+                       Ctrl3 |= PHY_B_P_SYM_MD;
+                       break;
+               case SK_FLOW_MODE_SYM_OR_REM:
+                       Ctrl3 |= PHY_B_P_BOTH_MD;
+                       break;
+               default:
+                       SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_HWI_E016,
+                               SKERR_HWI_E016MSG);
+               }
+
+               /* Restart Auto-negotiation */
+               Ctrl1 |= PHY_CT_ANE | PHY_CT_RE_CFG;
+       }
+       
+       /* Initialize LED register here? */
+       /* No. Please do it in SkDgXmitLed() (if required) and swap
+          init order of LEDs and XMAC. (MAl) */
+       
+       /* Write 1000Base-T Control Register */
+       SkXmPhyWrite(pAC, IoC, Port, PHY_BCOM_1000T_CTRL, Ctrl2);
+       SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+               ("Set 1000B-T Ctrl Reg=0x%04X\n", Ctrl2));
+       
+       /* Write AutoNeg Advertisement Register */
+       SkXmPhyWrite(pAC, IoC, Port, PHY_BCOM_AUNE_ADV, Ctrl3);
+       SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+               ("Set Auto-Neg.Adv.Reg=0x%04X\n", Ctrl3));
+       
+       if (DoLoop) {
+               /* Set the Phy Loopback bit, too */
+               Ctrl1 |= PHY_CT_LOOP;
+       }
+
+       if (pAC->GIni.GIPortUsage == SK_JUMBO_LINK) {
+               /* configure FIFO to high latency for transmission of ext. packets */
+               Ctrl4 |= PHY_B_PEC_HIGH_LA;
+
+               /* configure reception of extended packets */
+               Ctrl5 |= PHY_B_AC_LONG_PACK;
+
+               SkXmPhyWrite(pAC, IoC, Port, PHY_BCOM_AUX_CTRL, Ctrl5);
+       }
+
+       /* Configure LED Traffic Mode and Jumbo Frame usage if specified */
+       SkXmPhyWrite(pAC, IoC, Port, PHY_BCOM_P_EXT_CTRL, Ctrl4);
+       
+       /* Write to the Phy control register */
+       SkXmPhyWrite(pAC, IoC, Port, PHY_BCOM_CTRL, Ctrl1);
+       SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+               ("PHY Control Reg=0x%04X\n", Ctrl1));
+}      /* SkXmInitPhyBcom */
+#endif /* GENESIS */
+
+#ifdef YUKON
+/******************************************************************************
+ *
+ *     SkGmInitPhyMarv() - Initialize the Marvell Phy registers
+ *
+ * Description:        initializes all the Marvell Phy registers
+ *
+ * Note:
+ *
+ * Returns:
+ *     nothing
+ */
+static void SkGmInitPhyMarv(
+SK_AC  *pAC,           /* adapter context */
+SK_IOC IoC,            /* IO context */
+int            Port,           /* Port Index (MAC_1 + n) */
+SK_BOOL        DoLoop)         /* Should a Phy LoopBack be set-up? */
+{
+       SK_GEPORT       *pPrt;
+       SK_U16          PhyCtrl;
+       SK_U16          C1000BaseT;
+       SK_U16          AutoNegAdv;
+       SK_U16          ExtPhyCtrl;
+       SK_U16          LedCtrl;
+       SK_BOOL         AutoNeg;
+#if defined(SK_DIAG) || defined(DEBUG)
+       SK_U16          PhyStat;
+       SK_U16          PhyStat1;
+       SK_U16          PhySpecStat;
+#endif /* SK_DIAG || DEBUG */
+
+       pPrt = &pAC->GIni.GP[Port];
+
+       /* Auto-negotiation ? */
+       if (pPrt->PLinkMode == SK_LMODE_HALF || pPrt->PLinkMode == SK_LMODE_FULL) {
+               AutoNeg = SK_FALSE;
+       }
+       else {
+               AutoNeg = SK_TRUE;
+       }
+       
+       SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+               ("InitPhyMarv: Port %d, auto-negotiation %s\n",
+                Port, AutoNeg ? "ON" : "OFF"));
+
+#ifdef VCPU
+       VCPUprintf(0, "SkGmInitPhyMarv(), Port=%u, DoLoop=%u\n",
+               Port, DoLoop);
+#else /* VCPU */
+       if (DoLoop) {
+               /* Set 'MAC Power up'-bit, set Manual MDI configuration */
+               SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_PHY_CTRL,
+                       PHY_M_PC_MAC_POW_UP);
+       }
+       else if (AutoNeg && pPrt->PLinkSpeed == SK_LSPEED_AUTO) {
+               /* Read Ext. PHY Specific Control */
+               SkGmPhyRead(pAC, IoC, Port, PHY_MARV_EXT_CTRL, &ExtPhyCtrl);
+               
+               ExtPhyCtrl &= ~(PHY_M_EC_M_DSC_MSK | PHY_M_EC_S_DSC_MSK |
+                       PHY_M_EC_MAC_S_MSK);
+               
+               ExtPhyCtrl |= PHY_M_EC_MAC_S(MAC_TX_CLK_25_MHZ) |
+                       PHY_M_EC_M_DSC(0) | PHY_M_EC_S_DSC(1);
+       
+               SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_EXT_CTRL, ExtPhyCtrl);
+               SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+                       ("Set Ext. PHY Ctrl=0x%04X\n", ExtPhyCtrl));
+       }
+
+       /* Read PHY Control */
+       SkGmPhyRead(pAC, IoC, Port, PHY_MARV_CTRL, &PhyCtrl);
+
+       if (!AutoNeg) {
+               /* Disable Auto-negotiation */
+               PhyCtrl &= ~PHY_CT_ANE;
+       }
+
+       PhyCtrl |= PHY_CT_RESET;
+       /* Assert software reset */
+       SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_CTRL, PhyCtrl);
+#endif /* VCPU */
+
+       PhyCtrl = 0 /* PHY_CT_COL_TST */;
+       C1000BaseT = 0;
+       AutoNegAdv = PHY_SEL_TYPE;
+
+       /* manually Master/Slave ? */
+       if (pPrt->PMSMode != SK_MS_MODE_AUTO) {
+               /* enable Manual Master/Slave */
+               C1000BaseT |= PHY_M_1000C_MSE;
+               
+               if (pPrt->PMSMode == SK_MS_MODE_MASTER) {
+                       C1000BaseT |= PHY_M_1000C_MSC;  /* set it to Master */
+               }
+       }
+       
+       /* Auto-negotiation ? */
+       if (!AutoNeg) {
+               
+               if (pPrt->PLinkMode == SK_LMODE_FULL) {
+                       /* Set Full Duplex Mode */
+                       PhyCtrl |= PHY_CT_DUP_MD;
+               }
+
+               /* Set Master/Slave manually if not already done */
+               if (pPrt->PMSMode == SK_MS_MODE_AUTO) {
+                       C1000BaseT |= PHY_M_1000C_MSE;  /* set it to Slave */
+               }
+
+               /* Set Speed */
+               switch (pPrt->PLinkSpeed) {
+               case SK_LSPEED_AUTO:
+               case SK_LSPEED_1000MBPS:
+                       PhyCtrl |= PHY_CT_SP1000;
+                       break;
+               case SK_LSPEED_100MBPS:
+                       PhyCtrl |= PHY_CT_SP100;
+                       break;
+               case SK_LSPEED_10MBPS:
+                       break;
+               default:
+                       SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_HWI_E019,
+                               SKERR_HWI_E019MSG);
+               }
+
+               if (!DoLoop) {
+                       PhyCtrl |= PHY_CT_RESET;
+               }
+       }
+       else {
+               /* Set Auto-negotiation advertisement */
+               
+               if (pAC->GIni.GICopperType) {
+                       /* Set Speed capabilities */
+                       switch (pPrt->PLinkSpeed) {
+                       case SK_LSPEED_AUTO:
+                               C1000BaseT |= PHY_M_1000C_AHD | PHY_M_1000C_AFD;
+                               AutoNegAdv |= PHY_M_AN_100_FD | PHY_M_AN_100_HD |
+                                       PHY_M_AN_10_FD | PHY_M_AN_10_HD;
+                               break;
+                       case SK_LSPEED_1000MBPS:
+                               C1000BaseT |= PHY_M_1000C_AHD | PHY_M_1000C_AFD;
+                               break;
+                       case SK_LSPEED_100MBPS:
+                               AutoNegAdv |= PHY_M_AN_100_FD | PHY_M_AN_100_HD |
+                                       /* advertise 10Base-T also */
+                                       PHY_M_AN_10_FD | PHY_M_AN_10_HD;
+                               break;
+                       case SK_LSPEED_10MBPS:
+                               AutoNegAdv |= PHY_M_AN_10_FD | PHY_M_AN_10_HD;
+                               break;
+                       default:
+                               SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_HWI_E019,
+                                       SKERR_HWI_E019MSG);
+                       }
+
+                       /* Set Full/half duplex capabilities */
+                       switch (pPrt->PLinkMode) {
+                       case SK_LMODE_AUTOHALF:
+                               C1000BaseT &= ~PHY_M_1000C_AFD;
+                               AutoNegAdv &= ~(PHY_M_AN_100_FD | PHY_M_AN_10_FD);
+                               break;
+                       case SK_LMODE_AUTOFULL:
+                               C1000BaseT &= ~PHY_M_1000C_AHD;
+                               AutoNegAdv &= ~(PHY_M_AN_100_HD | PHY_M_AN_10_HD);
+                               break;
+                       case SK_LMODE_AUTOBOTH:
+                               break;
+                       default:
+                               SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_HWI_E015,
+                                       SKERR_HWI_E015MSG);
+                       }
+                       
+                       /* Set Flow-control capabilities */
+                       switch (pPrt->PFlowCtrlMode) {
+                       case SK_FLOW_MODE_NONE:
+                               AutoNegAdv |= PHY_B_P_NO_PAUSE;
+                               break;
+                       case SK_FLOW_MODE_LOC_SEND:
+                               AutoNegAdv |= PHY_B_P_ASYM_MD;
+                               break;
+                       case SK_FLOW_MODE_SYMMETRIC:
+                               AutoNegAdv |= PHY_B_P_SYM_MD;
+                               break;
+                       case SK_FLOW_MODE_SYM_OR_REM:
+                               AutoNegAdv |= PHY_B_P_BOTH_MD;
+                               break;
+                       default:
+                               SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_HWI_E016,
+                                       SKERR_HWI_E016MSG);
+                       }
+               }
+               else {  /* special defines for FIBER (88E1011S only) */
+                       
+                       /* Set Full/half duplex capabilities */
+                       switch (pPrt->PLinkMode) {
+                       case SK_LMODE_AUTOHALF:
+                               AutoNegAdv |= PHY_M_AN_1000X_AHD;
+                               break;
+                       case SK_LMODE_AUTOFULL:
+                               AutoNegAdv |= PHY_M_AN_1000X_AFD;
+                               break;
+                       case SK_LMODE_AUTOBOTH:
+                               AutoNegAdv |= PHY_M_AN_1000X_AHD | PHY_M_AN_1000X_AFD;
+                               break;
+                       default:
+                               SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_HWI_E015,
+                                       SKERR_HWI_E015MSG);
+                       }
+                       
+                       /* Set Flow-control capabilities */
+                       switch (pPrt->PFlowCtrlMode) {
+                       case SK_FLOW_MODE_NONE:
+                               AutoNegAdv |= PHY_M_P_NO_PAUSE_X;
+                               break;
+                       case SK_FLOW_MODE_LOC_SEND:
+                               AutoNegAdv |= PHY_M_P_ASYM_MD_X;
+                               break;
+                       case SK_FLOW_MODE_SYMMETRIC:
+                               AutoNegAdv |= PHY_M_P_SYM_MD_X;
+                               break;
+                       case SK_FLOW_MODE_SYM_OR_REM:
+                               AutoNegAdv |= PHY_M_P_BOTH_MD_X;
+                               break;
+                       default:
+                               SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_HWI_E016,
+                                       SKERR_HWI_E016MSG);
+                       }
+               }
+
+               if (!DoLoop) {
+                       /* Restart Auto-negotiation */
+                       PhyCtrl |= PHY_CT_ANE | PHY_CT_RE_CFG;
+               }
+       }
+       
+#ifdef VCPU
+       /*
+        * E-mail from Gu Lin (08-03-2002):
+        */
+       
+       /* Program PHY register 30 as 16'h0708 for simulation speed up */
+       SkGmPhyWrite(pAC, IoC, Port, 30, 0x0700 /* 0x0708 */);
+       
+       VCpuWait(2000);
+
+#else /* VCPU */
+       
+       /* Write 1000Base-T Control Register */
+       SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_1000T_CTRL, C1000BaseT);
+       SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+               ("Set 1000B-T Ctrl =0x%04X\n", C1000BaseT));
+       
+       /* Write AutoNeg Advertisement Register */
+       SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_AUNE_ADV, AutoNegAdv);
+       SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+               ("Set Auto-Neg.Adv.=0x%04X\n", AutoNegAdv));
+#endif /* VCPU */
+       
+       if (DoLoop) {
+               /* Set the PHY Loopback bit */
+               PhyCtrl |= PHY_CT_LOOP;
+
+#ifdef XXX
+               /* Program PHY register 16 as 16'h0400 to force link good */
+               SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_PHY_CTRL, PHY_M_PC_FL_GOOD);
+#endif /* XXX */
+
+#ifndef VCPU
+               if (pPrt->PLinkSpeed != SK_LSPEED_AUTO) {
+                       /* Write Ext. PHY Specific Control */
+                       SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_EXT_CTRL,
+                               (SK_U16)((pPrt->PLinkSpeed + 2) << 4));
+               }
+#endif /* VCPU */
+       }
+#ifdef TEST_ONLY
+       else if (pPrt->PLinkSpeed == SK_LSPEED_10MBPS) {
+                       /* Write PHY Specific Control */
+                       SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_PHY_CTRL,
+                               PHY_M_PC_EN_DET_MSK);
+       }
+#endif
+
+       /* Write to the PHY Control register */
+       SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_CTRL, PhyCtrl);
+       SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+               ("Set PHY Ctrl Reg.=0x%04X\n", PhyCtrl));
+
+#ifdef VCPU
+       VCpuWait(2000);
+#else
+
+       LedCtrl = PHY_M_LED_PULS_DUR(PULS_170MS) | PHY_M_LED_BLINK_RT(BLINK_84MS);
+
+       if ((pAC->GIni.GILedBlinkCtrl & SK_ACT_LED_BLINK) != 0) {
+               LedCtrl |= PHY_M_LEDC_RX_CTRL | PHY_M_LEDC_TX_CTRL;
+       }
+
+       if ((pAC->GIni.GILedBlinkCtrl & SK_DUP_LED_NORMAL) != 0) {
+               LedCtrl |= PHY_M_LEDC_DP_CTRL;
+       }
+       
+       SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_LED_CTRL, LedCtrl);
+
+       if ((pAC->GIni.GILedBlinkCtrl & SK_LED_LINK100_ON) != 0) {
+               /* only in forced 100 Mbps mode */
+               if (!AutoNeg && pPrt->PLinkSpeed == SK_LSPEED_100MBPS) {
+
+                       SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_LED_OVER,
+                               PHY_M_LED_MO_100(MO_LED_ON));
+               }
+       }
+
+#ifdef SK_DIAG
+       c_print("Set PHY Ctrl=0x%04X\n", PhyCtrl);
+       c_print("Set 1000 B-T=0x%04X\n", C1000BaseT);
+       c_print("Set Auto-Neg=0x%04X\n", AutoNegAdv);
+       c_print("Set Ext Ctrl=0x%04X\n", ExtPhyCtrl);
+#endif /* SK_DIAG */
+
+#if defined(SK_DIAG) || defined(DEBUG)
+       /* Read PHY Control */
+       SkGmPhyRead(pAC, IoC, Port, PHY_MARV_CTRL, &PhyCtrl);
+       SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+               ("PHY Ctrl Reg.=0x%04X\n", PhyCtrl));
+       
+       /* Read 1000Base-T Control Register */
+       SkGmPhyRead(pAC, IoC, Port, PHY_MARV_1000T_CTRL, &C1000BaseT);
+       SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+               ("1000B-T Ctrl =0x%04X\n", C1000BaseT));
+       
+       /* Read AutoNeg Advertisement Register */
+       SkGmPhyRead(pAC, IoC, Port, PHY_MARV_AUNE_ADV, &AutoNegAdv);
+       SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+               ("Auto-Neg.Adv.=0x%04X\n", AutoNegAdv));
+       
+       /* Read Ext. PHY Specific Control */
+       SkGmPhyRead(pAC, IoC, Port, PHY_MARV_EXT_CTRL, &ExtPhyCtrl);
+       SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+               ("Ext. PHY Ctrl=0x%04X\n", ExtPhyCtrl));
+       
+       /* Read PHY Status */
+       SkGmPhyRead(pAC, IoC, Port, PHY_MARV_STAT, &PhyStat);
+       SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+               ("PHY Stat Reg.=0x%04X\n", PhyStat));
+       SkGmPhyRead(pAC, IoC, Port, PHY_MARV_STAT, &PhyStat1);
+       SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+               ("PHY Stat Reg.=0x%04X\n", PhyStat1));
+       
+       /* Read PHY Specific Status */
+       SkGmPhyRead(pAC, IoC, Port, PHY_MARV_PHY_STAT, &PhySpecStat);
+       SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+               ("PHY Spec Stat=0x%04X\n", PhySpecStat));
+#endif /* SK_DIAG || DEBUG */
+
+#ifdef SK_DIAG
+       c_print("PHY Ctrl Reg=0x%04X\n", PhyCtrl);
+       c_print("PHY 1000 Reg=0x%04X\n", C1000BaseT);
+       c_print("PHY AnAd Reg=0x%04X\n", AutoNegAdv);
+       c_print("Ext Ctrl Reg=0x%04X\n", ExtPhyCtrl);
+       c_print("PHY Stat Reg=0x%04X\n", PhyStat);
+       c_print("PHY Stat Reg=0x%04X\n", PhyStat1);
+       c_print("PHY Spec Reg=0x%04X\n", PhySpecStat);
+#endif /* SK_DIAG */
+
+#endif /* VCPU */
+
+}      /* SkGmInitPhyMarv */
+#endif /* YUKON */
+
+
+#ifdef OTHER_PHY
+/******************************************************************************
+ *
+ *     SkXmInitPhyLone() - Initialize the Level One Phy registers
+ *
+ * Description:        initializes all the Level One Phy registers
+ *
+ * Note:
+ *
+ * Returns:
+ *     nothing
+ */
+static void SkXmInitPhyLone(
+SK_AC  *pAC,           /* adapter context */
+SK_IOC IoC,            /* IO context */
+int            Port,           /* Port Index (MAC_1 + n) */
+SK_BOOL        DoLoop)         /* Should a Phy LoopBack be set-up? */
+{
+       SK_GEPORT       *pPrt;
+       SK_U16          Ctrl1;
+       SK_U16          Ctrl2;
+       SK_U16          Ctrl3;
+
+       Ctrl1 = PHY_CT_SP1000;
+       Ctrl2 = 0;
+       Ctrl3 = PHY_SEL_TYPE;
+
+       pPrt = &pAC->GIni.GP[Port];
+
+       /* manually Master/Slave ? */
+       if (pPrt->PMSMode != SK_MS_MODE_AUTO) {
+               Ctrl2 |= PHY_L_1000C_MSE;
+               
+               if (pPrt->PMSMode == SK_MS_MODE_MASTER) {
+                       Ctrl2 |= PHY_L_1000C_MSC;
+               }
+       }
+       /* Auto-negotiation ? */
+       if (pPrt->PLinkMode == SK_LMODE_HALF || pPrt->PLinkMode == SK_LMODE_FULL) {
+               /*
+                * level one spec say: "1000 Mbps: manual mode not allowed"
+                * but lets see what happens...
+                */
+               SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+                       ("InitPhyLone: no auto-negotiation Port %d\n", Port));
+               /* Set DuplexMode in Config register */
+               if (pPrt->PLinkMode == SK_LMODE_FULL) {
+                       Ctrl1 |= PHY_CT_DUP_MD;
+               }
+
+               /* Determine Master/Slave manually if not already done */
+               if (pPrt->PMSMode == SK_MS_MODE_AUTO) {
+                       Ctrl2 |= PHY_L_1000C_MSE;       /* set it to Slave */
+               }
+
+               /*
+                * Do NOT enable Auto-negotiation here. This would hold
+                * the link down because no IDLES are transmitted
+                */
+       }
+       else {
+               SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+                       ("InitPhyLone: with auto-negotiation Port %d\n", Port));
+               /* Set Auto-negotiation advertisement */
+
+               /* Set Full/half duplex capabilities */
+               switch (pPrt->PLinkMode) {
+               case SK_LMODE_AUTOHALF:
+                       Ctrl2 |= PHY_L_1000C_AHD;
+                       break;
+               case SK_LMODE_AUTOFULL:
+                       Ctrl2 |= PHY_L_1000C_AFD;
+                       break;
+               case SK_LMODE_AUTOBOTH:
+                       Ctrl2 |= PHY_L_1000C_AFD | PHY_L_1000C_AHD;
+                       break;
+               default:
+                       SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_HWI_E015,
+                               SKERR_HWI_E015MSG);
+               }
+
+               /* Set Flow-control capabilities */
+               switch (pPrt->PFlowCtrlMode) {
+               case SK_FLOW_MODE_NONE:
+                       Ctrl3 |= PHY_L_P_NO_PAUSE;
+                       break;
+               case SK_FLOW_MODE_LOC_SEND:
+                       Ctrl3 |= PHY_L_P_ASYM_MD;
+                       break;
+               case SK_FLOW_MODE_SYMMETRIC:
+                       Ctrl3 |= PHY_L_P_SYM_MD;
+                       break;
+               case SK_FLOW_MODE_SYM_OR_REM:
+                       Ctrl3 |= PHY_L_P_BOTH_MD;
+                       break;
+               default:
+                       SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_HWI_E016,
+                               SKERR_HWI_E016MSG);
+               }
+
+               /* Restart Auto-negotiation */
+               Ctrl1 = PHY_CT_ANE | PHY_CT_RE_CFG;
+       }
+       
+       /* Write 1000Base-T Control Register */
+       SkXmPhyWrite(pAC, IoC, Port, PHY_LONE_1000T_CTRL, Ctrl2);
+       SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+               ("1000B-T Ctrl Reg=0x%04X\n", Ctrl2));
+       
+       /* Write AutoNeg Advertisement Register */
+       SkXmPhyWrite(pAC, IoC, Port, PHY_LONE_AUNE_ADV, Ctrl3);
+       SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+               ("Auto-Neg.Adv.Reg=0x%04X\n", Ctrl3));
+
+       if (DoLoop) {
+               /* Set the Phy Loopback bit, too */
+               Ctrl1 |= PHY_CT_LOOP;
+       }
+
+       /* Write to the Phy control register */
+       SkXmPhyWrite(pAC, IoC, Port, PHY_LONE_CTRL, Ctrl1);
+       SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+               ("PHY Control Reg=0x%04X\n", Ctrl1));
+}      /* SkXmInitPhyLone */
+
+
+/******************************************************************************
+ *
+ *     SkXmInitPhyNat() - Initialize the National Phy registers
+ *
+ * Description:        initializes all the National Phy registers
+ *
+ * Note:
+ *
+ * Returns:
+ *     nothing
+ */
+static void SkXmInitPhyNat(
+SK_AC  *pAC,           /* adapter context */
+SK_IOC IoC,            /* IO context */
+int            Port,           /* Port Index (MAC_1 + n) */
+SK_BOOL        DoLoop)         /* Should a Phy LoopBack be set-up? */
+{
+/* todo: National */
+}      /* SkXmInitPhyNat */
+#endif /* OTHER_PHY */
+
+
+/******************************************************************************
+ *
+ *     SkMacInitPhy() - Initialize the PHY registers
+ *
+ * Description:        calls the Init PHY routines dep. on board type
+ *
+ * Note:
+ *
+ * Returns:
+ *     nothing
+ */
+void SkMacInitPhy(
+SK_AC  *pAC,           /* adapter context */
+SK_IOC IoC,            /* IO context */
+int            Port,           /* Port Index (MAC_1 + n) */
+SK_BOOL        DoLoop)         /* Should a Phy LoopBack be set-up? */
+{
+       SK_GEPORT       *pPrt;
+
+       pPrt = &pAC->GIni.GP[Port];
+
+#ifdef GENESIS
+       if (pAC->GIni.GIGenesis) {
+               
+               switch (pPrt->PhyType) {
+               case SK_PHY_XMAC:
+                       SkXmInitPhyXmac(pAC, IoC, Port, DoLoop);
+                       break;
+               case SK_PHY_BCOM:
+                       SkXmInitPhyBcom(pAC, IoC, Port, DoLoop);
+                       break;
+#ifdef OTHER_PHY
+               case SK_PHY_LONE:
+                       SkXmInitPhyLone(pAC, IoC, Port, DoLoop);
+                       break;
+               case SK_PHY_NAT:
+                       SkXmInitPhyNat(pAC, IoC, Port, DoLoop);
+                       break;
+#endif /* OTHER_PHY */
+               }
+       }
+#endif /* GENESIS */
+       
+#ifdef YUKON
+       if (pAC->GIni.GIYukon) {
+               
+               SkGmInitPhyMarv(pAC, IoC, Port, DoLoop);
+       }
+#endif /* YUKON */
+
+}      /* SkMacInitPhy */
+
+
+#ifdef GENESIS
+/******************************************************************************
+ *
+ *     SkXmAutoNegDoneXmac() - Auto-negotiation handling
+ *
+ * Description:
+ *     This function handles the auto-negotiation if the Done bit is set.
+ *
+ * Returns:
+ *     SK_AND_OK       o.k.
+ *     SK_AND_DUP_CAP  Duplex capability error happened
+ *     SK_AND_OTHER    Other error happened
+ */
+static int SkXmAutoNegDoneXmac(
+SK_AC  *pAC,           /* adapter context */
+SK_IOC IoC,            /* IO context */
+int            Port)           /* Port Index (MAC_1 + n) */
+{
+       SK_GEPORT       *pPrt;
+       SK_U16          ResAb;          /* Resolved Ability */
+       SK_U16          LPAb;           /* Link Partner Ability */
+
+       SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+               ("AutoNegDoneXmac, Port %d\n", Port));
+
+       pPrt = &pAC->GIni.GP[Port];
+
+       /* Get PHY parameters */
+       SkXmPhyRead(pAC, IoC, Port, PHY_XMAC_AUNE_LP, &LPAb);
+       SkXmPhyRead(pAC, IoC, Port, PHY_XMAC_RES_ABI, &ResAb);
+
+       if ((LPAb & PHY_X_AN_RFB) != 0) {
+               /* At least one of the remote fault bit is set */
+               /* Error */
+               SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+                       ("AutoNegFail: Remote fault bit set Port %d\n", Port));
+               pPrt->PAutoNegFail = SK_TRUE;
+               return(SK_AND_OTHER);
+       }
+
+       /* Check Duplex mismatch */
+       if ((ResAb & (PHY_X_RS_HD | PHY_X_RS_FD)) == PHY_X_RS_FD) {
+               pPrt->PLinkModeStatus = (SK_U8)SK_LMODE_STAT_AUTOFULL;
+       }
+       else if ((ResAb & (PHY_X_RS_HD | PHY_X_RS_FD)) == PHY_X_RS_HD) {
+               pPrt->PLinkModeStatus = (SK_U8)SK_LMODE_STAT_AUTOHALF;
+       }
+       else {
+               /* Error */
+               SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+                       ("AutoNegFail: Duplex mode mismatch Port %d\n", Port));
+               pPrt->PAutoNegFail = SK_TRUE;
+               return(SK_AND_DUP_CAP);
+       }
+
+       /* Check PAUSE mismatch */
+       /* We are NOT using chapter 4.23 of the Xaqti manual */
+       /* We are using IEEE 802.3z/D5.0 Table 37-4 */
+       if ((pPrt->PFlowCtrlMode == SK_FLOW_MODE_SYMMETRIC ||
+            pPrt->PFlowCtrlMode == SK_FLOW_MODE_SYM_OR_REM) &&
+           (LPAb & PHY_X_P_SYM_MD) != 0) {
+               /* Symmetric PAUSE */
+               pPrt->PFlowCtrlStatus = SK_FLOW_STAT_SYMMETRIC;
+       }
+       else if (pPrt->PFlowCtrlMode == SK_FLOW_MODE_SYM_OR_REM &&
+                  (LPAb & PHY_X_RS_PAUSE) == PHY_X_P_ASYM_MD) {
+               /* Enable PAUSE receive, disable PAUSE transmit */
+               pPrt->PFlowCtrlStatus = SK_FLOW_STAT_REM_SEND;
+       }
+       else if (pPrt->PFlowCtrlMode == SK_FLOW_MODE_LOC_SEND &&
+                  (LPAb & PHY_X_RS_PAUSE) == PHY_X_P_BOTH_MD) {
+               /* Disable PAUSE receive, enable PAUSE transmit */
+               pPrt->PFlowCtrlStatus = SK_FLOW_STAT_LOC_SEND;
+       }
+       else {
+               /* PAUSE mismatch -> no PAUSE */
+               pPrt->PFlowCtrlStatus = SK_FLOW_STAT_NONE;
+       }
+       pPrt->PLinkSpeedUsed = (SK_U8)SK_LSPEED_STAT_1000MBPS;
+
+       return(SK_AND_OK);
+}      /* SkXmAutoNegDoneXmac */
+
+
+/******************************************************************************
+ *
+ *     SkXmAutoNegDoneBcom() - Auto-negotiation handling
+ *
+ * Description:
+ *     This function handles the auto-negotiation if the Done bit is set.
+ *
+ * Returns:
+ *     SK_AND_OK       o.k.
+ *     SK_AND_DUP_CAP  Duplex capability error happened
+ *     SK_AND_OTHER    Other error happened
+ */
+static int SkXmAutoNegDoneBcom(
+SK_AC  *pAC,           /* adapter context */
+SK_IOC IoC,            /* IO context */
+int            Port)           /* Port Index (MAC_1 + n) */
+{
+       SK_GEPORT       *pPrt;
+       SK_U16          LPAb;           /* Link Partner Ability */
+       SK_U16          AuxStat;        /* Auxiliary Status */
+
+#ifdef TEST_ONLY
+01-Sep-2000 RA;:;:
+       SK_U16          ResAb;          /* Resolved Ability */
+#endif /* 0 */
+
+       SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+               ("AutoNegDoneBcom, Port %d\n", Port));
+       pPrt = &pAC->GIni.GP[Port];
+
+       /* Get PHY parameters */
+       SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_AUNE_LP, &LPAb);
+#ifdef TEST_ONLY
+01-Sep-2000 RA;:;:
+       SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_1000T_STAT, &ResAb);
+#endif /* 0 */
+       
+       SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_AUX_STAT, &AuxStat);
+
+       if ((LPAb & PHY_B_AN_RF) != 0) {
+               /* Remote fault bit is set: Error */
+               SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+                       ("AutoNegFail: Remote fault bit set Port %d\n", Port));
+               pPrt->PAutoNegFail = SK_TRUE;
+               return(SK_AND_OTHER);
+       }
+
+       /* Check Duplex mismatch */
+       if ((AuxStat & PHY_B_AS_AN_RES_MSK) == PHY_B_RES_1000FD) {
+               pPrt->PLinkModeStatus = (SK_U8)SK_LMODE_STAT_AUTOFULL;
+       }
+       else if ((AuxStat & PHY_B_AS_AN_RES_MSK) == PHY_B_RES_1000HD) {
+               pPrt->PLinkModeStatus = (SK_U8)SK_LMODE_STAT_AUTOHALF;
+       }
+       else {
+               /* Error */
+               SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+                       ("AutoNegFail: Duplex mode mismatch Port %d\n", Port));
+               pPrt->PAutoNegFail = SK_TRUE;
+               return(SK_AND_DUP_CAP);
+       }
+       
+#ifdef TEST_ONLY
+01-Sep-2000 RA;:;:
+       /* Check Master/Slave resolution */
+       if ((ResAb & PHY_B_1000S_MSF) != 0) {
+               SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+                       ("Master/Slave Fault Port %d\n", Port));
+               pPrt->PAutoNegFail = SK_TRUE;
+               pPrt->PMSStatus = SK_MS_STAT_FAULT;
+               return(SK_AND_OTHER);
+       }
+       
+       pPrt->PMSStatus = ((ResAb & PHY_B_1000S_MSR) != 0) ?
+               SK_MS_STAT_MASTER : SK_MS_STAT_SLAVE;
+#endif /* 0 */
+
+       /* Check PAUSE mismatch ??? */
+       /* We are using IEEE 802.3z/D5.0 Table 37-4 */
+       if ((AuxStat & PHY_B_AS_PAUSE_MSK) == PHY_B_AS_PAUSE_MSK) {
+               /* Symmetric PAUSE */
+               pPrt->PFlowCtrlStatus = SK_FLOW_STAT_SYMMETRIC;
+       }
+       else if ((AuxStat & PHY_B_AS_PAUSE_MSK) == PHY_B_AS_PRR) {
+               /* Enable PAUSE receive, disable PAUSE transmit */
+               pPrt->PFlowCtrlStatus = SK_FLOW_STAT_REM_SEND;
+       }
+       else if ((AuxStat & PHY_B_AS_PAUSE_MSK) == PHY_B_AS_PRT) {
+               /* Disable PAUSE receive, enable PAUSE transmit */
+               pPrt->PFlowCtrlStatus = SK_FLOW_STAT_LOC_SEND;
+       }
+       else {
+               /* PAUSE mismatch -> no PAUSE */
+               pPrt->PFlowCtrlStatus = SK_FLOW_STAT_NONE;
+       }
+       pPrt->PLinkSpeedUsed = (SK_U8)SK_LSPEED_STAT_1000MBPS;
+
+       return(SK_AND_OK);
+}      /* SkXmAutoNegDoneBcom */
+#endif /* GENESIS */
+
+
+#ifdef YUKON
+/******************************************************************************
+ *
+ *     SkGmAutoNegDoneMarv() - Auto-negotiation handling
+ *
+ * Description:
+ *     This function handles the auto-negotiation if the Done bit is set.
+ *
+ * Returns:
+ *     SK_AND_OK       o.k.
+ *     SK_AND_DUP_CAP  Duplex capability error happened
+ *     SK_AND_OTHER    Other error happened
+ */
+static int SkGmAutoNegDoneMarv(
+SK_AC  *pAC,           /* adapter context */
+SK_IOC IoC,            /* IO context */
+int            Port)           /* Port Index (MAC_1 + n) */
+{
+       SK_GEPORT       *pPrt;
+       SK_U16          LPAb;           /* Link Partner Ability */
+       SK_U16          ResAb;          /* Resolved Ability */
+       SK_U16          AuxStat;        /* Auxiliary Status */
+
+       SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+               ("AutoNegDoneMarv, Port %d\n", Port));
+       pPrt = &pAC->GIni.GP[Port];
+
+       /* Get PHY parameters */
+       SkGmPhyRead(pAC, IoC, Port, PHY_MARV_AUNE_LP, &LPAb);
+       SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+               ("Link P.Abil.=0x%04X\n", LPAb));
+       
+       if ((LPAb & PHY_M_AN_RF) != 0) {
+               SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+                       ("AutoNegFail: Remote fault bit set Port %d\n", Port));
+               pPrt->PAutoNegFail = SK_TRUE;
+               return(SK_AND_OTHER);
+       }
+
+       SkGmPhyRead(pAC, IoC, Port, PHY_MARV_1000T_STAT, &ResAb);
+       
+       /* Check Master/Slave resolution */
+       if ((ResAb & PHY_B_1000S_MSF) != 0) {
+               SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+                       ("Master/Slave Fault Port %d\n", Port));
+               pPrt->PAutoNegFail = SK_TRUE;
+               pPrt->PMSStatus = SK_MS_STAT_FAULT;
+               return(SK_AND_OTHER);
+       }
+       
+       pPrt->PMSStatus = ((ResAb & PHY_B_1000S_MSR) != 0) ?
+               (SK_U8)SK_MS_STAT_MASTER : (SK_U8)SK_MS_STAT_SLAVE;
+       
+       /* Read PHY Specific Status */
+       SkGmPhyRead(pAC, IoC, Port, PHY_MARV_PHY_STAT, &AuxStat);
+       
+       /* Check Speed & Duplex resolved */
+       if ((AuxStat & PHY_M_PS_SPDUP_RES) == 0) {
+               SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+                       ("AutoNegFail: Speed & Duplex not resolved, Port %d\n", Port));
+               pPrt->PAutoNegFail = SK_TRUE;
+               pPrt->PLinkModeStatus = (SK_U8)SK_LMODE_STAT_UNKNOWN;
+               return(SK_AND_DUP_CAP);
+       }
+       
+       if ((AuxStat & PHY_M_PS_FULL_DUP) != 0) {
+               pPrt->PLinkModeStatus = (SK_U8)SK_LMODE_STAT_AUTOFULL;
+       }
+       else {
+               pPrt->PLinkModeStatus = (SK_U8)SK_LMODE_STAT_AUTOHALF;
+       }
+       
+       /* Check PAUSE mismatch ??? */
+       /* We are using IEEE 802.3z/D5.0 Table 37-4 */
+       if ((AuxStat & PHY_M_PS_PAUSE_MSK) == PHY_M_PS_PAUSE_MSK) {
+               /* Symmetric PAUSE */
+               pPrt->PFlowCtrlStatus = SK_FLOW_STAT_SYMMETRIC;
+       }
+       else if ((AuxStat & PHY_M_PS_PAUSE_MSK) == PHY_M_PS_RX_P_EN) {
+               /* Enable PAUSE receive, disable PAUSE transmit */
+               pPrt->PFlowCtrlStatus = SK_FLOW_STAT_REM_SEND;
+       }
+       else if ((AuxStat & PHY_M_PS_PAUSE_MSK) == PHY_M_PS_TX_P_EN) {
+               /* Disable PAUSE receive, enable PAUSE transmit */
+               pPrt->PFlowCtrlStatus = SK_FLOW_STAT_LOC_SEND;
+       }
+       else {
+               /* PAUSE mismatch -> no PAUSE */
+               pPrt->PFlowCtrlStatus = SK_FLOW_STAT_NONE;
+       }
+       
+       /* set used link speed */
+       switch ((unsigned)(AuxStat & PHY_M_PS_SPEED_MSK)) {
+       case (unsigned)PHY_M_PS_SPEED_1000:
+               pPrt->PLinkSpeedUsed = (SK_U8)SK_LSPEED_STAT_1000MBPS;
+               break;
+       case PHY_M_PS_SPEED_100:
+               pPrt->PLinkSpeedUsed = (SK_U8)SK_LSPEED_STAT_100MBPS;
+               break;
+       default:
+               pPrt->PLinkSpeedUsed = (SK_U8)SK_LSPEED_STAT_10MBPS;
+       }
+
+       return(SK_AND_OK);
+}      /* SkGmAutoNegDoneMarv */
+#endif /* YUKON */
+
+
+#ifdef OTHER_PHY
+/******************************************************************************
+ *
+ *     SkXmAutoNegDoneLone() - Auto-negotiation handling
+ *
+ * Description:
+ *     This function handles the auto-negotiation if the Done bit is set.
+ *
+ * Returns:
+ *     SK_AND_OK       o.k.
+ *     SK_AND_DUP_CAP  Duplex capability error happened
+ *     SK_AND_OTHER    Other error happened
+ */
+static int SkXmAutoNegDoneLone(
+SK_AC  *pAC,           /* adapter context */
+SK_IOC IoC,            /* IO context */
+int            Port)           /* Port Index (MAC_1 + n) */
+{
+       SK_GEPORT       *pPrt;
+       SK_U16          ResAb;          /* Resolved Ability */
+       SK_U16          LPAb;           /* Link Partner Ability */
+       SK_U16          QuickStat;      /* Auxiliary Status */
+
+       SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+               ("AutoNegDoneLone, Port %d\n", Port));
+       pPrt = &pAC->GIni.GP[Port];
+
+       /* Get PHY parameters */
+       SkXmPhyRead(pAC, IoC, Port, PHY_LONE_AUNE_LP, &LPAb);
+       SkXmPhyRead(pAC, IoC, Port, PHY_LONE_1000T_STAT, &ResAb);
+       SkXmPhyRead(pAC, IoC, Port, PHY_LONE_Q_STAT, &QuickStat);
+
+       if ((LPAb & PHY_L_AN_RF) != 0) {
+               /* Remote fault bit is set */
+               /* Error */
+               SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+                       ("AutoNegFail: Remote fault bit set Port %d\n", Port));
+               pPrt->PAutoNegFail = SK_TRUE;
+               return(SK_AND_OTHER);
+       }
+
+       /* Check Duplex mismatch */
+       if ((QuickStat & PHY_L_QS_DUP_MOD) != 0) {
+               pPrt->PLinkModeStatus = (SK_U8)SK_LMODE_STAT_AUTOFULL;
+       }
+       else {
+               pPrt->PLinkModeStatus = (SK_U8)SK_LMODE_STAT_AUTOHALF;
+       }
+       
+       /* Check Master/Slave resolution */
+       if ((ResAb & PHY_L_1000S_MSF) != 0) {
+               /* Error */
+               SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+                       ("Master/Slave Fault Port %d\n", Port));
+               pPrt->PAutoNegFail = SK_TRUE;
+               pPrt->PMSStatus = SK_MS_STAT_FAULT;
+               return(SK_AND_OTHER);
+       }
+       else if (ResAb & PHY_L_1000S_MSR) {
+               pPrt->PMSStatus = SK_MS_STAT_MASTER;
+       }
+       else {
+               pPrt->PMSStatus = SK_MS_STAT_SLAVE;
+       }
+
+       /* Check PAUSE mismatch */
+       /* We are using IEEE 802.3z/D5.0 Table 37-4 */
+       /* we must manually resolve the abilities here */
+       pPrt->PFlowCtrlStatus = SK_FLOW_STAT_NONE;
+       
+       switch (pPrt->PFlowCtrlMode) {
+       case SK_FLOW_MODE_NONE:
+               /* default */
+               break;
+       case SK_FLOW_MODE_LOC_SEND:
+               if ((QuickStat & (PHY_L_QS_PAUSE | PHY_L_QS_AS_PAUSE)) ==
+                       (PHY_L_QS_PAUSE | PHY_L_QS_AS_PAUSE)) {
+                       /* Disable PAUSE receive, enable PAUSE transmit */
+                       pPrt->PFlowCtrlStatus = SK_FLOW_STAT_LOC_SEND;
+               }
+               break;
+       case SK_FLOW_MODE_SYMMETRIC:
+               if ((QuickStat & PHY_L_QS_PAUSE) != 0) {
+                       /* Symmetric PAUSE */
+                       pPrt->PFlowCtrlStatus = SK_FLOW_STAT_SYMMETRIC;
+               }
+               break;
+       case SK_FLOW_MODE_SYM_OR_REM:
+               if ((QuickStat & (PHY_L_QS_PAUSE | PHY_L_QS_AS_PAUSE)) ==
+                       PHY_L_QS_AS_PAUSE) {
+                       /* Enable PAUSE receive, disable PAUSE transmit */
+                       pPrt->PFlowCtrlStatus = SK_FLOW_STAT_REM_SEND;
+               }
+               else if ((QuickStat & PHY_L_QS_PAUSE) != 0) {
+                       /* Symmetric PAUSE */
+                       pPrt->PFlowCtrlStatus = SK_FLOW_STAT_SYMMETRIC;
+               }
+               break;
+       default:
+               SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_HWI_E016,
+                       SKERR_HWI_E016MSG);
+       }
+       
+       return(SK_AND_OK);
+}      /* SkXmAutoNegDoneLone */
+
+
+/******************************************************************************
+ *
+ *     SkXmAutoNegDoneNat() - Auto-negotiation handling
+ *
+ * Description:
+ *     This function handles the auto-negotiation if the Done bit is set.
+ *
+ * Returns:
+ *     SK_AND_OK       o.k.
+ *     SK_AND_DUP_CAP  Duplex capability error happened
+ *     SK_AND_OTHER    Other error happened
+ */
+static int SkXmAutoNegDoneNat(
+SK_AC  *pAC,           /* adapter context */
+SK_IOC IoC,            /* IO context */
+int            Port)           /* Port Index (MAC_1 + n) */
+{
+/* todo: National */
+       return(SK_AND_OK);
+}      /* SkXmAutoNegDoneNat */
+#endif /* OTHER_PHY */
+
+
+/******************************************************************************
+ *
+ *     SkMacAutoNegDone() - Auto-negotiation handling
+ *
+ * Description:        calls the auto-negotiation done routines dep. on board type
+ *
+ * Returns:
+ *     SK_AND_OK       o.k.
+ *     SK_AND_DUP_CAP  Duplex capability error happened
+ *     SK_AND_OTHER    Other error happened
+ */
+int    SkMacAutoNegDone(
+SK_AC  *pAC,           /* adapter context */
+SK_IOC IoC,            /* IO context */
+int            Port)           /* Port Index (MAC_1 + n) */
+{
+       SK_GEPORT       *pPrt;
+       int     Rtv;
+
+       Rtv = SK_AND_OK;
+
+       pPrt = &pAC->GIni.GP[Port];
+
+#ifdef GENESIS
+       if (pAC->GIni.GIGenesis) {
+               
+               switch (pPrt->PhyType) {
+               
+               case SK_PHY_XMAC:
+                       Rtv = SkXmAutoNegDoneXmac(pAC, IoC, Port);
+                       break;
+               case SK_PHY_BCOM:
+                       Rtv = SkXmAutoNegDoneBcom(pAC, IoC, Port);
+                       break;
+#ifdef OTHER_PHY
+               case SK_PHY_LONE:
+                       Rtv = SkXmAutoNegDoneLone(pAC, IoC, Port);
+                       break;
+               case SK_PHY_NAT:
+                       Rtv = SkXmAutoNegDoneNat(pAC, IoC, Port);
+                       break;
+#endif /* OTHER_PHY */
+               default:
+                       return(SK_AND_OTHER);
+               }
+       }
+#endif /* GENESIS */
+       
+#ifdef YUKON
+       if (pAC->GIni.GIYukon) {
+               
+               Rtv = SkGmAutoNegDoneMarv(pAC, IoC, Port);
+       }
+#endif /* YUKON */
+       
+       if (Rtv != SK_AND_OK) {
+               return(Rtv);
+       }
+
+       SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+               ("AutoNeg done Port %d\n", Port));
+       
+       /* We checked everything and may now enable the link */
+       pPrt->PAutoNegFail = SK_FALSE;
+
+       SkMacRxTxEnable(pAC, IoC, Port);
+       
+       return(SK_AND_OK);
+}      /* SkMacAutoNegDone */
+
+
+/******************************************************************************
+ *
+ *     SkMacRxTxEnable() - Enable Rx/Tx activity if port is up
+ *
+ * Description:        enables Rx/Tx dep. on board type
+ *
+ * Returns:
+ *     0       o.k.
+ *     != 0    Error happened
+ */
+int SkMacRxTxEnable(
+SK_AC  *pAC,           /* adapter context */
+SK_IOC IoC,            /* IO context */
+int            Port)           /* Port Index (MAC_1 + n) */
+{
+       SK_GEPORT       *pPrt;
+       SK_U16          Reg;            /* 16-bit register value */
+       SK_U16          IntMask;        /* MAC interrupt mask */
+#ifdef GENESIS
+       SK_U16          SWord;
+#endif
+
+       pPrt = &pAC->GIni.GP[Port];
+
+       if (!pPrt->PHWLinkUp) {
+               /* The Hardware link is NOT up */
+               return(0);
+       }
+
+       if ((pPrt->PLinkMode == SK_LMODE_AUTOHALF ||
+            pPrt->PLinkMode == SK_LMODE_AUTOFULL ||
+            pPrt->PLinkMode == SK_LMODE_AUTOBOTH) &&
+            pPrt->PAutoNegFail) {
+               /* Auto-negotiation is not done or failed */
+               return(0);
+       }
+
+#ifdef GENESIS
+       if (pAC->GIni.GIGenesis) {
+               /* set Duplex Mode and Pause Mode */
+               SkXmInitDupMd(pAC, IoC, Port);
+               
+               SkXmInitPauseMd(pAC, IoC, Port);
+       
+               /*
+                * Initialize the Interrupt Mask Register. Default IRQs are...
+                *      - Link Asynchronous Event
+                *      - Link Partner requests config
+                *      - Auto Negotiation Done
+                *      - Rx Counter Event Overflow
+                *      - Tx Counter Event Overflow
+                *      - Transmit FIFO Underrun
+                */
+               IntMask = XM_DEF_MSK;
+
+#ifdef DEBUG
+               /* add IRQ for Receive FIFO Overflow */
+               IntMask &= ~XM_IS_RXF_OV;
+#endif /* DEBUG */
+               
+               if (pPrt->PhyType != SK_PHY_XMAC) {
+                       /* disable GP0 interrupt bit */
+                       IntMask |= XM_IS_INP_ASS;
+               }
+               XM_OUT16(IoC, Port, XM_IMSK, IntMask);
+       
+               /* get MMU Command Reg. */
+               XM_IN16(IoC, Port, XM_MMU_CMD, &Reg);
+               
+               if (pPrt->PhyType != SK_PHY_XMAC &&
+                       (pPrt->PLinkModeStatus == SK_LMODE_STAT_FULL ||
+                        pPrt->PLinkModeStatus == SK_LMODE_STAT_AUTOFULL)) {
+                       /* set to Full Duplex */
+                       Reg |= XM_MMU_GMII_FD;
+               }
+               
+               switch (pPrt->PhyType) {
+               case SK_PHY_BCOM:
+                       /*
+                        * Workaround BCOM Errata (#10523) for all BCom Phys
+                        * Enable Power Management after link up
+                        */
+                       SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_AUX_CTRL, &SWord);
+                       SkXmPhyWrite(pAC, IoC, Port, PHY_BCOM_AUX_CTRL,
+                               (SK_U16)(SWord & ~PHY_B_AC_DIS_PM));
+            SkXmPhyWrite(pAC, IoC, Port, PHY_BCOM_INT_MASK,
+                               (SK_U16)PHY_B_DEF_MSK);
+                       break;
+#ifdef OTHER_PHY
+               case SK_PHY_LONE:
+                       SkXmPhyWrite(pAC, IoC, Port, PHY_LONE_INT_ENAB, PHY_L_DEF_MSK);
+                       break;
+               case SK_PHY_NAT:
+                       /* todo National:
+                       SkXmPhyWrite(pAC, IoC, Port, PHY_NAT_INT_MASK, PHY_N_DEF_MSK); */
+                       /* no interrupts possible from National ??? */
+                       break;
+#endif /* OTHER_PHY */
+               }
+               
+               /* enable Rx/Tx */
+               XM_OUT16(IoC, Port, XM_MMU_CMD, Reg | XM_MMU_ENA_RX | XM_MMU_ENA_TX);
+       }
+#endif /* GENESIS */
+       
+#ifdef YUKON
+       if (pAC->GIni.GIYukon) {
+               /*
+                * Initialize the Interrupt Mask Register. Default IRQs are...
+                *      - Rx Counter Event Overflow
+                *      - Tx Counter Event Overflow
+                *      - Transmit FIFO Underrun
+                */
+               IntMask = GMAC_DEF_MSK;
+
+#ifdef DEBUG
+               /* add IRQ for Receive FIFO Overrun */
+               IntMask |= GM_IS_RX_FF_OR;
+#endif /* DEBUG */
+               
+               SK_OUT8(IoC, GMAC_IRQ_MSK, (SK_U8)IntMask);
+               
+               /* get General Purpose Control */
+               GM_IN16(IoC, Port, GM_GP_CTRL, &Reg);
+               
+               if (pPrt->PLinkModeStatus == SK_LMODE_STAT_FULL ||
+                       pPrt->PLinkModeStatus == SK_LMODE_STAT_AUTOFULL) {
+                       /* set to Full Duplex */
+                       Reg |= GM_GPCR_DUP_FULL;
+               }
+               
+               /* enable Rx/Tx */
+        GM_OUT16(IoC, Port, GM_GP_CTRL, (SK_U16)(Reg | GM_GPCR_RX_ENA |
+                       GM_GPCR_TX_ENA));
+
+#ifndef VCPU
+               /* Enable all PHY interrupts */
+        SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_INT_MASK,
+                       (SK_U16)PHY_M_DEF_MSK);
+#endif /* VCPU */
+       }
+#endif /* YUKON */
+                                       
+       return(0);
+
+}      /* SkMacRxTxEnable */
+
+
+/******************************************************************************
+ *
+ *     SkMacRxTxDisable() - Disable Receiver and Transmitter
+ *
+ * Description:        disables Rx/Tx dep. on board type
+ *
+ * Returns: N/A
+ */
+void SkMacRxTxDisable(
+SK_AC  *pAC,           /* Adapter Context */
+SK_IOC IoC,            /* IO context */
+int            Port)           /* Port Index (MAC_1 + n) */
+{
+       SK_U16  Word;
+
+#ifdef GENESIS
+       if (pAC->GIni.GIGenesis) {
+               
+               XM_IN16(IoC, Port, XM_MMU_CMD, &Word);
+               
+               XM_OUT16(IoC, Port, XM_MMU_CMD, Word & ~(XM_MMU_ENA_RX | XM_MMU_ENA_TX));
+       
+               /* dummy read to ensure writing */
+               XM_IN16(IoC, Port, XM_MMU_CMD, &Word);
+       }
+#endif /* GENESIS */
+       
+#ifdef YUKON
+       if (pAC->GIni.GIYukon) {
+               
+               GM_IN16(IoC, Port, GM_GP_CTRL, &Word);
+
+        GM_OUT16(IoC, Port, GM_GP_CTRL, (SK_U16)(Word & ~(GM_GPCR_RX_ENA |
+                       GM_GPCR_TX_ENA)));
+
+               /* dummy read to ensure writing */
+               GM_IN16(IoC, Port, GM_GP_CTRL, &Word);
+       }
+#endif /* YUKON */
+
+}      /* SkMacRxTxDisable */
+
+
+/******************************************************************************
+ *
+ *     SkMacIrqDisable() - Disable IRQ from MAC
+ *
+ * Description:        sets the IRQ-mask to disable IRQ dep. on board type
+ *
+ * Returns: N/A
+ */
+void SkMacIrqDisable(
+SK_AC  *pAC,           /* Adapter Context */
+SK_IOC IoC,            /* IO context */
+int            Port)           /* Port Index (MAC_1 + n) */
+{
+       SK_GEPORT       *pPrt;
+#ifdef GENESIS
+       SK_U16          Word;
+#endif
+
+       pPrt = &pAC->GIni.GP[Port];
+
+#ifdef GENESIS
+       if (pAC->GIni.GIGenesis) {
+               
+               /* disable all XMAC IRQs */
+               XM_OUT16(IoC, Port, XM_IMSK, 0xffff);   
+               
+               /* Disable all PHY interrupts */
+               switch (pPrt->PhyType) {
+                       case SK_PHY_BCOM:
+                               /* Make sure that PHY is initialized */
+                               if (pPrt->PState != SK_PRT_RESET) {
+                                       /* NOT allowed if BCOM is in RESET state */
+                                       /* Workaround BCOM Errata (#10523) all BCom */
+                                       /* Disable Power Management if link is down */
+                                       SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_AUX_CTRL, &Word);
+                                       SkXmPhyWrite(pAC, IoC, Port, PHY_BCOM_AUX_CTRL,
+                                               (SK_U16)(Word | PHY_B_AC_DIS_PM));
+                                       SkXmPhyWrite(pAC, IoC, Port, PHY_BCOM_INT_MASK, 0xffff);
+                               }
+                               break;
+#ifdef OTHER_PHY
+                       case SK_PHY_LONE:
+                               SkXmPhyWrite(pAC, IoC, Port, PHY_LONE_INT_ENAB, 0);
+                               break;
+                       case SK_PHY_NAT:
+                               /* todo: National
+                               SkXmPhyWrite(pAC, IoC, Port, PHY_NAT_INT_MASK, 0xffff); */
+                               break;
+#endif /* OTHER_PHY */
+               }
+       }
+#endif /* GENESIS */
+       
+#ifdef YUKON
+       if (pAC->GIni.GIYukon) {
+               /* disable all GMAC IRQs */
+               SK_OUT8(IoC, GMAC_IRQ_MSK, 0);
+               
+#ifndef VCPU
+               /* Disable all PHY interrupts */
+               SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_INT_MASK, 0);
+#endif /* VCPU */
+       }
+#endif /* YUKON */
+
+}      /* SkMacIrqDisable */
+
+
+#ifdef SK_DIAG
+/******************************************************************************
+ *
+ *     SkXmSendCont() - Enable / Disable Send Continuous Mode
+ *
+ * Description:        enable / disable Send Continuous Mode on XMAC
+ *
+ * Returns:
+ *     nothing
+ */
+void SkXmSendCont(
+SK_AC  *pAC,   /* adapter context */
+SK_IOC IoC,    /* IO context */
+int            Port,   /* Port Index (MAC_1 + n) */
+SK_BOOL        Enable) /* Enable / Disable */
+{
+       SK_U32  MdReg;
+
+       XM_IN32(IoC, Port, XM_MODE, &MdReg);
+
+       if (Enable) {
+               MdReg |= XM_MD_TX_CONT;
+       }
+       else {
+               MdReg &= ~XM_MD_TX_CONT;
+       }
+       /* setup Mode Register */
+       XM_OUT32(IoC, Port, XM_MODE, MdReg);
+
+}      /* SkXmSendCont */
+
+
+/******************************************************************************
+ *
+ *     SkMacTimeStamp() - Enable / Disable Time Stamp
+ *
+ * Description:        enable / disable Time Stamp generation for Rx packets
+ *
+ * Returns:
+ *     nothing
+ */
+void SkMacTimeStamp(
+SK_AC  *pAC,   /* adapter context */
+SK_IOC IoC,    /* IO context */
+int            Port,   /* Port Index (MAC_1 + n) */
+SK_BOOL        Enable) /* Enable / Disable */
+{
+       SK_U32  MdReg;
+       SK_U8   TimeCtrl;
+
+       if (pAC->GIni.GIGenesis) {
+
+               XM_IN32(IoC, Port, XM_MODE, &MdReg);
+
+               if (Enable) {
+                       MdReg |= XM_MD_ATS;
+               }
+               else {
+                       MdReg &= ~XM_MD_ATS;
+               }
+               /* setup Mode Register */
+               XM_OUT32(IoC, Port, XM_MODE, MdReg);
+       }
+       else {
+               if (Enable) {
+                       TimeCtrl = GMT_ST_START | GMT_ST_CLR_IRQ;
+               }
+               else {
+                       TimeCtrl = GMT_ST_STOP | GMT_ST_CLR_IRQ;
+               }
+               /* Start/Stop Time Stamp Timer */
+               SK_OUT8(IoC, GMAC_TI_ST_CTRL, TimeCtrl);
+       }
+
+}      /* SkMacTimeStamp*/
+
+#else /* !SK_DIAG */
+
+#ifdef GENESIS
+/******************************************************************************
+ *
+ *     SkXmAutoNegLipaXmac() - Decides whether Link Partner could do auto-neg
+ *
+ *     This function analyses the Interrupt status word. If any of the
+ *     Auto-negotiating interrupt bits are set, the PLipaAutoNeg variable
+ *     is set true.
+ */
+void SkXmAutoNegLipaXmac(
+SK_AC  *pAC,           /* adapter context */
+SK_IOC IoC,            /* IO context */
+int            Port,           /* Port Index (MAC_1 + n) */
+SK_U16 IStatus)        /* Interrupt Status word to analyse */
+{
+       SK_GEPORT       *pPrt;
+
+       pPrt = &pAC->GIni.GP[Port];
+
+       if (pPrt->PLipaAutoNeg != SK_LIPA_AUTO &&
+               (IStatus & (XM_IS_LIPA_RC | XM_IS_RX_PAGE | XM_IS_AND)) != 0) {
+
+               SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+                       ("AutoNegLipa: AutoNeg detected on Port %d, IStatus=0x%04X\n",
+                       Port, IStatus));
+               pPrt->PLipaAutoNeg = SK_LIPA_AUTO;
+       }
+}      /* SkXmAutoNegLipaXmac */
+#endif /* GENESIS */
+
+
+/******************************************************************************
+ *
+ *     SkMacAutoNegLipaPhy() - Decides whether Link Partner could do auto-neg
+ *
+ *     This function analyses the PHY status word.
+ *  If any of the Auto-negotiating bits are set, the PLipaAutoNeg variable
+ *     is set true.
+ */
+void SkMacAutoNegLipaPhy(
+SK_AC  *pAC,           /* adapter context */
+SK_IOC IoC,            /* IO context */
+int            Port,           /* Port Index (MAC_1 + n) */
+SK_U16 PhyStat)        /* PHY Status word to analyse */
+{
+       SK_GEPORT       *pPrt;
+
+       pPrt = &pAC->GIni.GP[Port];
+
+       if (pPrt->PLipaAutoNeg != SK_LIPA_AUTO &&
+               (PhyStat & PHY_ST_AN_OVER) != 0) {
+
+               SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+                       ("AutoNegLipa: AutoNeg detected on Port %d, PhyStat=0x%04X\n",
+                       Port, PhyStat));
+               pPrt->PLipaAutoNeg = SK_LIPA_AUTO;
+       }
+}      /* SkMacAutoNegLipaPhy */
+
+
+#ifdef GENESIS
+/******************************************************************************
+ *
+ *     SkXmIrq() - Interrupt Service Routine
+ *
+ * Description:        services an Interrupt Request of the XMAC
+ *
+ * Note:
+ *     With an external PHY, some interrupt bits are not meaningfull any more:
+ *     - LinkAsyncEvent (bit #14)              XM_IS_LNK_AE
+ *     - LinkPartnerReqConfig (bit #10)        XM_IS_LIPA_RC
+ *     - Page Received (bit #9)                XM_IS_RX_PAGE
+ *     - NextPageLoadedForXmt (bit #8)         XM_IS_TX_PAGE
+ *     - AutoNegDone (bit #7)                  XM_IS_AND
+ *     Also probably not valid any more is the GP0 input bit:
+ *     - GPRegisterBit0set                     XM_IS_INP_ASS
+ *
+ * Returns:
+ *     nothing
+ */
+static void SkXmIrq(
+SK_AC  *pAC,           /* adapter context */
+SK_IOC IoC,            /* IO context */
+int            Port)           /* Port Index (MAC_1 + n) */
+{
+       SK_GEPORT       *pPrt;
+       SK_EVPARA       Para;
+       SK_U16          IStatus;        /* Interrupt status read from the XMAC */
+       SK_U16          IStatus2;
+#ifdef SK_SLIM
+    SK_U64      OverflowStatus;
+#endif 
+
+       pPrt = &pAC->GIni.GP[Port];
+       
+       XM_IN16(IoC, Port, XM_ISRC, &IStatus);
+       
+       /* LinkPartner Auto-negable? */
+       if (pPrt->PhyType == SK_PHY_XMAC) {
+               SkXmAutoNegLipaXmac(pAC, IoC, Port, IStatus);
+       }
+       else {
+               /* mask bits that are not used with ext. PHY */
+               IStatus &= ~(XM_IS_LNK_AE | XM_IS_LIPA_RC |
+                       XM_IS_RX_PAGE | XM_IS_TX_PAGE |
+                       XM_IS_AND | XM_IS_INP_ASS);
+       }
+       
+       SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ,
+               ("XmacIrq Port %d Isr 0x%04X\n", Port, IStatus));
+
+       if (!pPrt->PHWLinkUp) {
+               /* Spurious XMAC interrupt */
+               SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ,
+                       ("SkXmIrq: spurious interrupt on Port %d\n", Port));
+               return;
+       }
+
+       if ((IStatus & XM_IS_INP_ASS) != 0) {
+               /* Reread ISR Register if link is not in sync */
+               XM_IN16(IoC, Port, XM_ISRC, &IStatus2);
+
+               SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ,
+                       ("SkXmIrq: Link async. Double check Port %d 0x%04X 0x%04X\n",
+                        Port, IStatus, IStatus2));
+               IStatus &= ~XM_IS_INP_ASS;
+               IStatus |= IStatus2;
+       }
+
+       if ((IStatus & XM_IS_LNK_AE) != 0) {
+               /* not used, GP0 is used instead */
+       }
+
+       if ((IStatus & XM_IS_TX_ABORT) != 0) {
+               /* not used */
+       }
+
+       if ((IStatus & XM_IS_FRC_INT) != 0) {
+               /* not used, use ASIC IRQ instead if needed */
+       }
+
+       if ((IStatus & (XM_IS_INP_ASS | XM_IS_LIPA_RC | XM_IS_RX_PAGE)) != 0) {
+               SkHWLinkDown(pAC, IoC, Port);
+
+               /* Signal to RLMT */
+               Para.Para32[0] = (SK_U32)Port;
+               SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_LINK_DOWN, Para);
+
+               /* Start workaround Errata #2 timer */
+               SkTimerStart(pAC, IoC, &pPrt->PWaTimer, SK_WA_INA_TIME,
+                       SKGE_HWAC, SK_HWEV_WATIM, Para);
+       }
+
+       if ((IStatus & XM_IS_RX_PAGE) != 0) {
+               /* not used */
+       }
+
+       if ((IStatus & XM_IS_TX_PAGE) != 0) {
+               /* not used */
+       }
+
+       if ((IStatus & XM_IS_AND) != 0) {
+               SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ,
+                       ("SkXmIrq: AND on link that is up Port %d\n", Port));
+       }
+
+       if ((IStatus & XM_IS_TSC_OV) != 0) {
+               /* not used */
+       }
+
+       /* Combined Tx & Rx Counter Overflow SIRQ Event */
+       if ((IStatus & (XM_IS_RXC_OV | XM_IS_TXC_OV)) != 0) {
+#ifdef SK_SLIM
+               SkXmOverflowStatus(pAC, IoC, Port, IStatus, &OverflowStatus);
+#else
+               Para.Para32[0] = (SK_U32)Port;
+               Para.Para32[1] = (SK_U32)IStatus;
+               SkPnmiEvent(pAC, IoC, SK_PNMI_EVT_SIRQ_OVERFLOW, Para);
+#endif /* SK_SLIM */
+       }
+
+       if ((IStatus & XM_IS_RXF_OV) != 0) {
+               /* normal situation -> no effect */
+#ifdef DEBUG
+               pPrt->PRxOverCnt++;
+#endif /* DEBUG */
+       }
+
+       if ((IStatus & XM_IS_TXF_UR) != 0) {
+               /* may NOT happen -> error log */
+               SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_SIRQ_E020, SKERR_SIRQ_E020MSG);
+       }
+
+       if ((IStatus & XM_IS_TX_COMP) != 0) {
+               /* not served here */
+       }
+
+       if ((IStatus & XM_IS_RX_COMP) != 0) {
+               /* not served here */
+       }
+}      /* SkXmIrq */
+#endif /* GENESIS */
+
+
+#ifdef YUKON
+/******************************************************************************
+ *
+ *     SkGmIrq() - Interrupt Service Routine
+ *
+ * Description:        services an Interrupt Request of the GMAC
+ *
+ * Note:
+ *
+ * Returns:
+ *     nothing
+ */
+static void SkGmIrq(
+SK_AC  *pAC,           /* adapter context */
+SK_IOC IoC,            /* IO context */
+int            Port)           /* Port Index (MAC_1 + n) */
+{
+       SK_GEPORT       *pPrt;
+       SK_U8           IStatus;        /* Interrupt status */
+#ifdef SK_SLIM
+    SK_U64      OverflowStatus;
+#else
+       SK_EVPARA       Para;
+#endif 
+
+       pPrt = &pAC->GIni.GP[Port];
+       
+       SK_IN8(IoC, GMAC_IRQ_SRC, &IStatus);
+       
+#ifdef XXX
+       /* LinkPartner Auto-negable? */
+       SkMacAutoNegLipaPhy(pAC, IoC, Port, IStatus);
+#endif /* XXX */
+       
+       SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ,
+               ("GmacIrq Port %d Isr 0x%04X\n", Port, IStatus));
+
+       /* Combined Tx & Rx Counter Overflow SIRQ Event */
+       if (IStatus & (GM_IS_RX_CO_OV | GM_IS_TX_CO_OV)) {
+               /* these IRQs will be cleared by reading GMACs register */
+#ifdef SK_SLIM
+        SkGmOverflowStatus(pAC, IoC, Port, IStatus, &OverflowStatus);
+#else
+               Para.Para32[0] = (SK_U32)Port;
+               Para.Para32[1] = (SK_U32)IStatus;
+               SkPnmiEvent(pAC, IoC, SK_PNMI_EVT_SIRQ_OVERFLOW, Para);
+#endif         
+       }
+
+       if (IStatus & GM_IS_RX_FF_OR) {
+               /* clear GMAC Rx FIFO Overrun IRQ */
+               SK_OUT8(IoC, MR_ADDR(Port, RX_GMF_CTRL_T), (SK_U8)GMF_CLI_RX_FO);
+#ifdef DEBUG
+               pPrt->PRxOverCnt++;
+#endif /* DEBUG */
+       }
+
+       if (IStatus & GM_IS_TX_FF_UR) {
+               /* clear GMAC Tx FIFO Underrun IRQ */
+               SK_OUT8(IoC, MR_ADDR(Port, TX_GMF_CTRL_T), (SK_U8)GMF_CLI_TX_FU);
+               /* may NOT happen -> error log */
+               SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_SIRQ_E020, SKERR_SIRQ_E020MSG);
+       }
+
+       if (IStatus & GM_IS_TX_COMPL) {
+               /* not served here */
+       }
+
+       if (IStatus & GM_IS_RX_COMPL) {
+               /* not served here */
+       }
+}      /* SkGmIrq */
+#endif /* YUKON */
+
+
+/******************************************************************************
+ *
+ *     SkMacIrq() - Interrupt Service Routine for MAC
+ *
+ * Description:        calls the Interrupt Service Routine dep. on board type
+ *
+ * Returns:
+ *     nothing
+ */
+void SkMacIrq(
+SK_AC  *pAC,           /* adapter context */
+SK_IOC IoC,            /* IO context */
+int            Port)           /* Port Index (MAC_1 + n) */
+{
+#ifdef GENESIS
+       if (pAC->GIni.GIGenesis) {
+               /* IRQ from XMAC */
+               SkXmIrq(pAC, IoC, Port);
+       }
+#endif /* GENESIS */
+       
+#ifdef YUKON
+       if (pAC->GIni.GIYukon) {
+               /* IRQ from GMAC */
+               SkGmIrq(pAC, IoC, Port);
+       }
+#endif /* YUKON */
+
+}      /* SkMacIrq */
+
+#endif /* !SK_DIAG */
+
+#ifdef GENESIS
+/******************************************************************************
+ *
+ *     SkXmUpdateStats() - Force the XMAC to output the current statistic
+ *
+ * Description:
+ *     The XMAC holds its statistic internally. To obtain the current
+ *     values a command must be sent so that the statistic data will
+ *     be written to a predefined memory area on the adapter.
+ *
+ * Returns:
+ *     0:  success
+ *     1:  something went wrong
+ */
+int SkXmUpdateStats(
+SK_AC  *pAC,           /* adapter context */
+SK_IOC IoC,            /* IO context */
+unsigned int Port)     /* Port Index (MAC_1 + n) */
+{
+       SK_GEPORT       *pPrt;
+       SK_U16          StatReg;
+       int                     WaitIndex;
+
+       pPrt = &pAC->GIni.GP[Port];
+       WaitIndex = 0;
+
+       /* Send an update command to XMAC specified */
+       XM_OUT16(IoC, Port, XM_STAT_CMD, XM_SC_SNP_TXC | XM_SC_SNP_RXC);
+
+       /*
+        * It is an auto-clearing register. If the command bits
+        * went to zero again, the statistics are transferred.
+        * Normally the command should be executed immediately.
+        * But just to be sure we execute a loop.
+        */
+       do {
+
+               XM_IN16(IoC, Port, XM_STAT_CMD, &StatReg);
+               
+               if (++WaitIndex > 10) {
+
+                       SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_HWI_E021, SKERR_HWI_E021MSG);
+
+                       return(1);
+               }
+       } while ((StatReg & (XM_SC_SNP_TXC | XM_SC_SNP_RXC)) != 0);
+       
+       return(0);
+}      /* SkXmUpdateStats */
+
+
+/******************************************************************************
+ *
+ *     SkXmMacStatistic() - Get XMAC counter value
+ *
+ * Description:
+ *     Gets the 32bit counter value. Except for the octet counters
+ *     the lower 32bit are counted in hardware and the upper 32bit
+ *     must be counted in software by monitoring counter overflow interrupts.
+ *
+ * Returns:
+ *     0:  success
+ *     1:  something went wrong
+ */
+int SkXmMacStatistic(
+SK_AC  *pAC,                   /* adapter context */
+SK_IOC IoC,                    /* IO context */
+unsigned int Port,             /* Port Index (MAC_1 + n) */
+SK_U16 StatAddr,               /* MIB counter base address */
+SK_U32 SK_FAR *pVal)   /* ptr to return statistic value */
+{
+       if ((StatAddr < XM_TXF_OK) || (StatAddr > XM_RXF_MAX_SZ)) {
+               
+               SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E022, SKERR_HWI_E022MSG);
+               
+               return(1);
+       }
+       
+       XM_IN32(IoC, Port, StatAddr, pVal);
+
+       return(0);
+}      /* SkXmMacStatistic */
+
+
+/******************************************************************************
+ *
+ *     SkXmResetCounter() - Clear MAC statistic counter
+ *
+ * Description:
+ *     Force the XMAC to clear its statistic counter.
+ *
+ * Returns:
+ *     0:  success
+ *     1:  something went wrong
+ */
+int SkXmResetCounter(
+SK_AC  *pAC,           /* adapter context */
+SK_IOC IoC,            /* IO context */
+unsigned int Port)     /* Port Index (MAC_1 + n) */
+{
+       XM_OUT16(IoC, Port, XM_STAT_CMD, XM_SC_CLR_RXC | XM_SC_CLR_TXC);
+       /* Clear two times according to Errata #3 */
+       XM_OUT16(IoC, Port, XM_STAT_CMD, XM_SC_CLR_RXC | XM_SC_CLR_TXC);
+
+       return(0);
+}      /* SkXmResetCounter */
+
+
+/******************************************************************************
+ *
+ *     SkXmOverflowStatus() - Gets the status of counter overflow interrupt
+ *
+ * Description:
+ *     Checks the source causing an counter overflow interrupt. On success the
+ *     resulting counter overflow status is written to <pStatus>, whereas the
+ *     upper dword stores the XMAC ReceiveCounterEvent register and the lower
+ *     dword the XMAC TransmitCounterEvent register.
+ *
+ * Note:
+ *     For XMAC the interrupt source is a self-clearing register, so the source
+ *     must be checked only once. SIRQ module does another check to be sure
+ *     that no interrupt get lost during process time.
+ *
+ * Returns:
+ *     0:  success
+ *     1:  something went wrong
+ */
+int SkXmOverflowStatus(
+SK_AC  *pAC,                           /* adapter context */
+SK_IOC IoC,                            /* IO context */
+unsigned int Port,                     /* Port Index (MAC_1 + n) */
+SK_U16 IStatus,                        /* Interupt Status from MAC */
+SK_U64 SK_FAR *pStatus)        /* ptr for return overflow status value */
+{
+       SK_U64  Status; /* Overflow status */
+       SK_U32  RegVal;
+
+       Status = 0;
+
+       if ((IStatus & XM_IS_RXC_OV) != 0) {
+
+               XM_IN32(IoC, Port, XM_RX_CNT_EV, &RegVal);
+               Status |= (SK_U64)RegVal << 32;
+       }
+       
+       if ((IStatus & XM_IS_TXC_OV) != 0) {
+
+               XM_IN32(IoC, Port, XM_TX_CNT_EV, &RegVal);
+               Status |= (SK_U64)RegVal;
+       }
+
+       *pStatus = Status;
+
+       return(0);
+}      /* SkXmOverflowStatus */
+#endif /* GENESIS */
+
+
+#ifdef YUKON
+/******************************************************************************
+ *
+ *     SkGmUpdateStats() - Force the GMAC to output the current statistic
+ *
+ * Description:
+ *     Empty function for GMAC. Statistic data is accessible in direct way.
+ *
+ * Returns:
+ *     0:  success
+ *     1:  something went wrong
+ */
+int SkGmUpdateStats(
+SK_AC  *pAC,           /* adapter context */
+SK_IOC IoC,            /* IO context */
+unsigned int Port)     /* Port Index (MAC_1 + n) */
+{
+       return(0);
+}
+
+
+/******************************************************************************
+ *
+ *     SkGmMacStatistic() - Get GMAC counter value
+ *
+ * Description:
+ *     Gets the 32bit counter value. Except for the octet counters
+ *     the lower 32bit are counted in hardware and the upper 32bit
+ *     must be counted in software by monitoring counter overflow interrupts.
+ *
+ * Returns:
+ *     0:  success
+ *     1:  something went wrong
+ */
+int SkGmMacStatistic(
+SK_AC  *pAC,                   /* adapter context */
+SK_IOC IoC,                    /* IO context */
+unsigned int Port,             /* Port Index (MAC_1 + n) */
+SK_U16 StatAddr,               /* MIB counter base address */
+SK_U32 SK_FAR *pVal)   /* ptr to return statistic value */
+{
+
+       if ((StatAddr < GM_RXF_UC_OK) || (StatAddr > GM_TXE_FIFO_UR)) {
+               
+               SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E022, SKERR_HWI_E022MSG);
+               
+               SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+                       ("SkGmMacStat: wrong MIB counter 0x%04X\n", StatAddr));
+               return(1);
+       }
+               
+       GM_IN32(IoC, Port, StatAddr, pVal);
+
+       return(0);
+}      /* SkGmMacStatistic */
+
+
+/******************************************************************************
+ *
+ *     SkGmResetCounter() - Clear MAC statistic counter
+ *
+ * Description:
+ *     Force GMAC to clear its statistic counter.
+ *
+ * Returns:
+ *     0:  success
+ *     1:  something went wrong
+ */
+int SkGmResetCounter(
+SK_AC  *pAC,           /* adapter context */
+SK_IOC IoC,            /* IO context */
+unsigned int Port)     /* Port Index (MAC_1 + n) */
+{
+       SK_U16  Reg;    /* Phy Address Register */
+       SK_U16  Word;
+       int             i;
+
+       GM_IN16(IoC, Port, GM_PHY_ADDR, &Reg);
+
+       /* set MIB Clear Counter Mode */
+       GM_OUT16(IoC, Port, GM_PHY_ADDR, Reg | GM_PAR_MIB_CLR);
+       
+       /* read all MIB Counters with Clear Mode set */
+       for (i = 0; i < GM_MIB_CNT_SIZE; i++) {
+               /* the reset is performed only when the lower 16 bits are read */
+               GM_IN16(IoC, Port, GM_MIB_CNT_BASE + 8*i, &Word);
+       }
+       
+       /* clear MIB Clear Counter Mode */
+       GM_OUT16(IoC, Port, GM_PHY_ADDR, Reg);
+       
+       return(0);
+}      /* SkGmResetCounter */
+
+
+/******************************************************************************
+ *
+ *     SkGmOverflowStatus() - Gets the status of counter overflow interrupt
+ *
+ * Description:
+ *     Checks the source causing an counter overflow interrupt. On success the
+ *     resulting counter overflow status is written to <pStatus>, whereas the
+ *     the following bit coding is used:
+ *     63:56 - unused
+ *     55:48 - TxRx interrupt register bit7:0
+ *     32:47 - Rx interrupt register
+ *     31:24 - unused
+ *     23:16 - TxRx interrupt register bit15:8
+ *     15:0  - Tx interrupt register
+ *
+ * Returns:
+ *     0:  success
+ *     1:  something went wrong
+ */
+int SkGmOverflowStatus(
+SK_AC  *pAC,                           /* adapter context */
+SK_IOC IoC,                            /* IO context */
+unsigned int Port,                     /* Port Index (MAC_1 + n) */
+SK_U16 IStatus,                        /* Interupt Status from MAC */
+SK_U64 SK_FAR *pStatus)        /* ptr for return overflow status value */
+{
+       SK_U64  Status;         /* Overflow status */
+       SK_U16  RegVal;
+
+       Status = 0;
+
+       if ((IStatus & GM_IS_RX_CO_OV) != 0) {
+               /* this register is self-clearing after read */
+               GM_IN16(IoC, Port, GM_RX_IRQ_SRC, &RegVal);
+               Status |= (SK_U64)RegVal << 32;
+       }
+       
+       if ((IStatus & GM_IS_TX_CO_OV) != 0) {
+               /* this register is self-clearing after read */
+               GM_IN16(IoC, Port, GM_TX_IRQ_SRC, &RegVal);
+               Status |= (SK_U64)RegVal;
+       }
+       
+       /* this register is self-clearing after read */
+       GM_IN16(IoC, Port, GM_TR_IRQ_SRC, &RegVal);
+       /* Rx overflow interrupt register bits (LoByte)*/
+       Status |= (SK_U64)((SK_U8)RegVal) << 48;
+       /* Tx overflow interrupt register bits (HiByte)*/
+       Status |= (SK_U64)(RegVal >> 8) << 16;
+
+       *pStatus = Status;
+
+       return(0);
+}      /* SkGmOverflowStatus */
+
+
+#ifndef SK_SLIM
+/******************************************************************************
+ *
+ *     SkGmCableDiagStatus() - Starts / Gets status of cable diagnostic test
+ *
+ * Description:
+ *  starts the cable diagnostic test if 'StartTest' is true
+ *  gets the results if 'StartTest' is true
+ *
+ * NOTE:       this test is meaningful only when link is down
+ *     
+ * Returns:
+ *     0:  success
+ *     1:      no YUKON copper
+ *     2:      test in progress
+ */
+int SkGmCableDiagStatus(
+SK_AC  *pAC,           /* adapter context */
+SK_IOC IoC,            /* IO context */
+int            Port,           /* Port Index (MAC_1 + n) */
+SK_BOOL        StartTest)      /* flag for start / get result */
+{
+       int             i;
+       SK_U16  RegVal;
+       SK_GEPORT       *pPrt;
+
+       pPrt = &pAC->GIni.GP[Port];
+
+       if (pPrt->PhyType != SK_PHY_MARV_COPPER) {
+               
+               return(1);
+       }
+
+       if (StartTest) {
+               /* only start the cable test */
+               if ((pPrt->PhyId1 & PHY_I1_REV_MSK) < 4) {
+                       /* apply TDR workaround from Marvell */
+                       SkGmPhyWrite(pAC, IoC, Port, 29, 0x001e);
+                       
+                       SkGmPhyWrite(pAC, IoC, Port, 30, 0xcc00);
+                       SkGmPhyWrite(pAC, IoC, Port, 30, 0xc800);
+                       SkGmPhyWrite(pAC, IoC, Port, 30, 0xc400);
+                       SkGmPhyWrite(pAC, IoC, Port, 30, 0xc000);
+                       SkGmPhyWrite(pAC, IoC, Port, 30, 0xc100);
+               }
+
+               /* set address to 0 for MDI[0] */
+               SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_EXT_ADR, 0);
+
+               /* Read Cable Diagnostic Reg */
+               SkGmPhyRead(pAC, IoC, Port, PHY_MARV_CABLE_DIAG, &RegVal);
+
+               /* start Cable Diagnostic Test */
+               SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_CABLE_DIAG,
+                       (SK_U16)(RegVal | PHY_M_CABD_ENA_TEST));
+       
+               return(0);
+       }
+       
+       /* Read Cable Diagnostic Reg */
+       SkGmPhyRead(pAC, IoC, Port, PHY_MARV_CABLE_DIAG, &RegVal);
+
+       SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+               ("PHY Cable Diag.=0x%04X\n", RegVal));
+
+       if ((RegVal & PHY_M_CABD_ENA_TEST) != 0) {
+               /* test is running */
+               return(2);
+       }
+
+       /* get the test results */
+       for (i = 0; i < 4; i++)  {
+               /* set address to i for MDI[i] */
+               SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_EXT_ADR, (SK_U16)i);
+
+               /* get Cable Diagnostic values */
+               SkGmPhyRead(pAC, IoC, Port, PHY_MARV_CABLE_DIAG, &RegVal);
+
+               pPrt->PMdiPairLen[i] = (SK_U8)(RegVal & PHY_M_CABD_DIST_MSK);
+
+               pPrt->PMdiPairSts[i] = (SK_U8)((RegVal & PHY_M_CABD_STAT_MSK) >> 13);
+       }
+
+       return(0);
+}      /* SkGmCableDiagStatus */
+#endif /* !SK_SLIM */
+#endif /* YUKON */
+
+/* End of file */