summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/ManagementStyle2
-rw-r--r--Documentation/feature-removal-schedule.txt8
-rw-r--r--Documentation/kernel-parameters.txt3
-rw-r--r--Documentation/networking/00-INDEX3
-rw-r--r--Documentation/networking/sk98lin.txt568
-rw-r--r--Documentation/thinkpad-acpi.txt96
-rw-r--r--Documentation/video4linux/cx2341x/fw-encoder-api.txt4
-rw-r--r--arch/arm/mach-realview/realview_eb.c2
-rw-r--r--arch/arm/vfp/vfpmodule.c1
-rw-r--r--arch/blackfin/mach-common/pm.c6
-rw-r--r--arch/i386/xen/enlighten.c4
-rw-r--r--arch/mips/dec/setup.c2
-rw-r--r--arch/mips/kernel/cpu-bugs64.c4
-rw-r--r--arch/mips/kernel/cpu-probe.c9
-rw-r--r--arch/mips/kernel/rtlx.c4
-rw-r--r--arch/mips/kernel/scall64-n32.S2
-rw-r--r--arch/mips/kernel/time.c1
-rw-r--r--arch/mips/mips-boards/malta/malta_int.c2
-rw-r--r--arch/mips/mm/tlbex.c26
-rw-r--r--arch/powerpc/kernel/time.c8
-rw-r--r--arch/powerpc/kernel/vdso.c12
-rw-r--r--arch/powerpc/platforms/cell/spufs/sched.c4
-rw-r--r--arch/sparc64/defconfig16
-rw-r--r--arch/sparc64/kernel/head.S35
-rw-r--r--arch/sparc64/kernel/mdesc.c6
-rw-r--r--arch/sparc64/kernel/prom.c6
-rw-r--r--arch/sparc64/kernel/trampoline.S33
-rw-r--r--arch/sparc64/prom/misc.c16
-rw-r--r--arch/um/include/kern_util.h2
-rw-r--r--arch/um/kernel/irq.c7
-rw-r--r--arch/um/os-Linux/file.c3
-rw-r--r--arch/um/os-Linux/signal.c4
-rw-r--r--arch/x86_64/mm/fault.c7
-rw-r--r--arch/xtensa/Makefile7
-rw-r--r--arch/xtensa/kernel/Makefile2
-rw-r--r--arch/xtensa/kernel/asm-offsets.c13
-rw-r--r--arch/xtensa/kernel/entry.S115
-rw-r--r--arch/xtensa/kernel/init_task.c38
-rw-r--r--arch/xtensa/kernel/io.c75
-rw-r--r--arch/xtensa/kernel/module.c195
-rw-r--r--arch/xtensa/kernel/pci.c69
-rw-r--r--arch/xtensa/kernel/process.c14
-rw-r--r--arch/xtensa/kernel/semaphore.c2
-rw-r--r--arch/xtensa/kernel/syscall.c5
-rw-r--r--arch/xtensa/kernel/time.c46
-rw-r--r--arch/xtensa/kernel/traps.c4
-rw-r--r--arch/xtensa/mm/Makefile6
-rw-r--r--arch/xtensa/mm/cache.c256
-rw-r--r--arch/xtensa/mm/fault.c6
-rw-r--r--arch/xtensa/mm/init.c252
-rw-r--r--arch/xtensa/mm/misc.S306
-rw-r--r--arch/xtensa/platform-iss/console.c1
-rw-r--r--block/ll_rw_blk.c23
-rw-r--r--drivers/acpi/event.c2
-rw-r--r--drivers/acpi/processor_core.c21
-rw-r--r--drivers/acpi/sleep/proc.c10
-rw-r--r--drivers/base/core.c29
-rw-r--r--drivers/block/DAC960.c1
-rw-r--r--drivers/char/agp/agp.h3
-rw-r--r--drivers/char/agp/intel-agp.c2
-rw-r--r--drivers/char/ipmi/ipmi_si_intf.c3
-rw-r--r--drivers/char/mspec.c69
-rw-r--r--drivers/char/tty_ioctl.c14
-rw-r--r--drivers/ide/ide-disk.c1
-rw-r--r--drivers/ide/ppc/pmac.c2
-rw-r--r--drivers/kvm/kvm.h10
-rw-r--r--drivers/kvm/mmu.c5
-rw-r--r--drivers/md/dm-bio-list.h3
-rw-r--r--drivers/media/video/cx88/cx88-mpeg.c2
-rw-r--r--drivers/media/video/ivtv/ivtv-fileops.c6
-rw-r--r--drivers/media/video/ivtv/ivtv-ioctl.c17
-rw-r--r--drivers/media/video/pwc/pwc-if.c2
-rw-r--r--drivers/media/video/saa7134/saa7134-cards.c12
-rw-r--r--drivers/media/video/saa7191.c4
-rw-r--r--drivers/media/video/usbvision/usbvision-cards.c1
-rw-r--r--drivers/misc/Kconfig20
-rw-r--r--drivers/misc/msi-laptop.c2
-rw-r--r--drivers/misc/thinkpad_acpi.c144
-rw-r--r--drivers/misc/thinkpad_acpi.h1
-rw-r--r--drivers/mtd/nand/cafe_nand.c3
-rw-r--r--drivers/net/Kconfig89
-rw-r--r--drivers/net/Makefile1
-rw-r--r--drivers/net/atl1/atl1_main.c19
-rw-r--r--drivers/net/ehea/ehea.h5
-rw-r--r--drivers/net/ehea/ehea_main.c16
-rw-r--r--drivers/net/mv643xx_eth.c2
-rw-r--r--drivers/net/pcmcia/3c589_cs.c2
-rw-r--r--drivers/net/phy/phy.c4
-rw-r--r--drivers/net/phy/phy_device.c4
-rw-r--r--drivers/net/ppp_generic.c58
-rw-r--r--drivers/net/pppoe.c70
-rw-r--r--drivers/net/sk98lin/Makefile87
-rw-r--r--drivers/net/sk98lin/h/lm80.h179
-rw-r--r--drivers/net/sk98lin/h/skaddr.h285
-rw-r--r--drivers/net/sk98lin/h/skcsum.h213
-rw-r--r--drivers/net/sk98lin/h/skdebug.h74
-rw-r--r--drivers/net/sk98lin/h/skdrv1st.h188
-rw-r--r--drivers/net/sk98lin/h/skdrv2nd.h447
-rw-r--r--drivers/net/sk98lin/h/skerror.h55
-rw-r--r--drivers/net/sk98lin/h/skgedrv.h51
-rw-r--r--drivers/net/sk98lin/h/skgehw.h2126
-rw-r--r--drivers/net/sk98lin/h/skgehwt.h48
-rw-r--r--drivers/net/sk98lin/h/skgei2c.h210
-rw-r--r--drivers/net/sk98lin/h/skgeinit.h797
-rw-r--r--drivers/net/sk98lin/h/skgepnm2.h334
-rw-r--r--drivers/net/sk98lin/h/skgepnmi.h962
-rw-r--r--drivers/net/sk98lin/h/skgesirq.h110
-rw-r--r--drivers/net/sk98lin/h/ski2c.h174
-rw-r--r--drivers/net/sk98lin/h/skqueue.h94
-rw-r--r--drivers/net/sk98lin/h/skrlmt.h438
-rw-r--r--drivers/net/sk98lin/h/sktimer.h63
-rw-r--r--drivers/net/sk98lin/h/sktypes.h69
-rw-r--r--drivers/net/sk98lin/h/skversion.h38
-rw-r--r--drivers/net/sk98lin/h/skvpd.h248
-rw-r--r--drivers/net/sk98lin/h/xmac_ii.h1579
-rw-r--r--drivers/net/sk98lin/skaddr.c1788
-rw-r--r--drivers/net/sk98lin/skdim.c742
-rw-r--r--drivers/net/sk98lin/skethtool.c627
-rw-r--r--drivers/net/sk98lin/skge.c5219
-rw-r--r--drivers/net/sk98lin/skgehwt.c171
-rw-r--r--drivers/net/sk98lin/skgeinit.c2005
-rw-r--r--drivers/net/sk98lin/skgemib.c1075
-rw-r--r--drivers/net/sk98lin/skgepnmi.c8210
-rw-r--r--drivers/net/sk98lin/skgesirq.c2229
-rw-r--r--drivers/net/sk98lin/ski2c.c1296
-rw-r--r--drivers/net/sk98lin/sklm80.c141
-rw-r--r--drivers/net/sk98lin/skqueue.c179
-rw-r--r--drivers/net/sk98lin/skrlmt.c3257
-rw-r--r--drivers/net/sk98lin/sktimer.c250
-rw-r--r--drivers/net/sk98lin/skvpd.c1091
-rw-r--r--drivers/net/sk98lin/skxmac2.c4160
-rw-r--r--drivers/net/sky2.c9
-rw-r--r--drivers/net/spider_net.c12
-rw-r--r--drivers/net/ucc_geth.c2
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_main.c28
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_main.h2
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c2
-rw-r--r--drivers/rtc/rtc-ds1553.c2
-rw-r--r--drivers/rtc/rtc-ds1742.c2
-rw-r--r--drivers/serial/sunsab.c107
-rw-r--r--drivers/usb/core/quirks.c6
-rw-r--r--drivers/usb/storage/scsiglue.c13
-rw-r--r--drivers/usb/storage/usb.c27
-rw-r--r--drivers/video/aty/ati_ids.h12
-rw-r--r--drivers/video/aty/radeon_base.c6
-rw-r--r--drivers/video/intelfb/intelfbhw.c2
-rw-r--r--fs/compat_ioctl.c22
-rw-r--r--fs/ext3/namei.c73
-rw-r--r--fs/ext4/namei.c73
-rw-r--r--fs/nfs/super.c2
-rw-r--r--fs/xfs/linux-2.6/xfs_aops.c1
-rw-r--r--fs/xfs/linux-2.6/xfs_super.c4
-rw-r--r--fs/xfs/xfs_buf_item.h5
-rw-r--r--fs/xfs/xfs_filestream.c3
-rw-r--r--fs/xfs/xfs_log_recover.c51
-rw-r--r--fs/xfs/xfs_mru_cache.c72
-rw-r--r--fs/xfs/xfs_mru_cache.h6
-rw-r--r--fs/xfs/xfs_trans_buf.c1
-rw-r--r--fs/xfs/xfs_vnodeops.c20
-rw-r--r--include/asm-blackfin/mach-bf561/cdefBF561.h4
-rw-r--r--include/asm-blackfin/string.h129
-rw-r--r--include/asm-mips/compiler.h4
-rw-r--r--include/asm-mips/mach-generic/ide.h31
-rw-r--r--include/asm-powerpc/time.h5
-rw-r--r--include/asm-sparc64/oplib.h4
-rw-r--r--include/asm-xtensa/bugs.h6
-rw-r--r--include/asm-xtensa/cache.h9
-rw-r--r--include/asm-xtensa/cacheflush.h81
-rw-r--r--include/asm-xtensa/elf.h50
-rw-r--r--include/asm-xtensa/io.h1
-rw-r--r--include/asm-xtensa/ioctls.h4
-rw-r--r--include/asm-xtensa/page.h106
-rw-r--r--include/asm-xtensa/pgalloc.h107
-rw-r--r--include/asm-xtensa/pgtable.h235
-rw-r--r--include/asm-xtensa/processor.h2
-rw-r--r--include/asm-xtensa/syscall.h24
-rw-r--r--include/asm-xtensa/termbits.h5
-rw-r--r--include/asm-xtensa/termios.h6
-rw-r--r--include/asm-xtensa/timex.h4
-rw-r--r--include/asm-xtensa/tlb.h30
-rw-r--r--include/asm-xtensa/types.h9
-rw-r--r--include/asm-xtensa/unistd.h128
-rw-r--r--include/linux/isa.h11
-rw-r--r--include/linux/mempolicy.h4
-rw-r--r--include/linux/sched.h3
-rw-r--r--include/linux/skbuff.h40
-rw-r--r--include/linux/user_namespace.h2
-rw-r--r--include/media/v4l2-dev.h5
-rw-r--r--include/net/sctp/sctp.h1
-rw-r--r--include/net/sctp/structs.h13
-rw-r--r--init/Kconfig1
-rw-r--r--init/do_mounts_initrd.c4
-rw-r--r--kernel/time/tick-broadcast.c24
-rw-r--r--kernel/time/tick-sched.c12
-rw-r--r--kernel/time/timekeeping.c10
-rw-r--r--kernel/user.c45
-rw-r--r--kernel/user_namespace.c4
-rw-r--r--kernel/utsname.c2
-rw-r--r--mm/hugetlb.c4
-rw-r--r--mm/mempolicy.c79
-rw-r--r--net/8021q/vlan.c2
-rw-r--r--net/bridge/br_device.c4
-rw-r--r--net/bridge/br_forward.c21
-rw-r--r--net/bridge/br_input.c48
-rw-r--r--net/bridge/br_netfilter.c2
-rw-r--r--net/bridge/br_private.h8
-rw-r--r--net/core/pktgen.c10
-rw-r--r--net/core/sock.c106
-rw-r--r--net/ipv4/udp.c6
-rw-r--r--net/ipv6/addrconf.c2
-rw-r--r--net/ipv6/raw.c3
-rw-r--r--net/ipv6/udp.c6
-rw-r--r--net/sched/act_api.c8
-rw-r--r--net/sched/act_police.c4
-rw-r--r--net/sched/sch_cbq.c2
-rw-r--r--net/sctp/associola.c14
-rw-r--r--net/sctp/bind_addr.c70
-rw-r--r--net/sctp/endpointola.c27
-rw-r--r--net/sctp/ipv6.c46
-rw-r--r--net/sctp/protocol.c79
-rw-r--r--net/sctp/sm_make_chunk.c18
-rw-r--r--net/sctp/socket.c134
-rw-r--r--net/sunrpc/svcsock.c2
223 files changed, 45075 insertions, 1669 deletions
diff --git a/Documentation/ManagementStyle b/Documentation/ManagementStyle
index cbbebfb51ff..49a8efa5afe 100644
--- a/Documentation/ManagementStyle
+++ b/Documentation/ManagementStyle
@@ -166,7 +166,7 @@ To solve this problem, you really only have two options:
The option of being unfailingly polite really doesn't exist. Nobody will
trust somebody who is so clearly hiding his true character.
-(*) Paul Simon sang "Fifty Ways to Lose Your Lover", because quite
+(*) Paul Simon sang "Fifty Ways to Leave Your Lover", because quite
frankly, "A Million Ways to Tell a Developer He Is a D*ckhead" doesn't
scan nearly as well. But I'm sure he thought about it.
diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt
index b9a3fdc1cc5..00928d2ecfb 100644
--- a/Documentation/feature-removal-schedule.txt
+++ b/Documentation/feature-removal-schedule.txt
@@ -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>
+
+---------------------------
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index b41cde31d11..4d175c75124 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -468,9 +468,6 @@ and is between 256 and 4096 characters. It is defined in the file
Format:
<first_slot>,<last_slot>,<port>,<enum_bit>[,<debug>]
- cpia_pp= [HW,PPT]
- Format: { parport<nr> | auto | none }
-
crashkernel=nn[KMG]@ss[KMG]
[KNL] Reserve a chunk of physical memory to
hold a kernel to switch to with kexec on panic.
diff --git a/Documentation/networking/00-INDEX b/Documentation/networking/00-INDEX
index d63f480afb7..153d84d281e 100644
--- a/Documentation/networking/00-INDEX
+++ b/Documentation/networking/00-INDEX
@@ -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
index 00000000000..8590a954df1
--- /dev/null
+++ b/Documentation/networking/sk98lin.txt
@@ -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***
diff --git a/Documentation/thinkpad-acpi.txt b/Documentation/thinkpad-acpi.txt
index eb2f5986e1e..60953d6c919 100644
--- a/Documentation/thinkpad-acpi.txt
+++ b/Documentation/thinkpad-acpi.txt
@@ -1,7 +1,7 @@
ThinkPad ACPI Extras Driver
- Version 0.15
- July 1st, 2007
+ Version 0.16
+ August 2nd, 2007
Borislav Deianov <borislav@users.sf.net>
Henrique de Moraes Holschuh <hmh@hmh.eng.br>
@@ -161,20 +161,22 @@ system. Enabling the hotkey functionality of thinkpad-acpi signals the
firmware that such a driver is present, and modifies how the ThinkPad
firmware will behave in many situations.
+The driver enables the hot key feature automatically when loaded. The
+feature can later be disabled and enabled back at runtime. The driver
+will also restore the hot key feature to its previous state and mask
+when it is unloaded.
+
When the hotkey feature is enabled and the hot key mask is set (see
-below), the various hot keys either generate ACPI events in the
-following format:
+below), the driver will report HKEY events in the following format:
ibm/hotkey HKEY 00000080 0000xxxx
-or events over the input layer. The input layer support accepts the
-standard IOCTLs to remap the keycodes assigned to each hotkey.
+Some of these events refer to hot key presses, but not all.
-When the input device is open, the driver will suppress any ACPI hot key
-events that get translated into a meaningful input layer event, in order
-to avoid sending duplicate events to userspace. Hot keys that are
-mapped to KEY_RESERVED in the keymap are not translated, and will always
-generate an ACPI ibm/hotkey HKEY event, and no input layer events.
+The driver will generate events over the input layer for hot keys and
+radio switches, and over the ACPI netlink layer for other events. The
+input layer support accepts the standard IOCTLs to remap the keycodes
+assigned to each hot key.
The hot key bit mask allows some control over which hot keys generate
events. If a key is "masked" (bit set to 0 in the mask), the firmware
@@ -256,6 +258,20 @@ sysfs notes:
disabled" postition, and 1 if the switch is in the
"radios enabled" position.
+ hotkey_report_mode:
+ Returns the state of the procfs ACPI event report mode
+ filter for hot keys. If it is set to 1 (the default),
+ all hot key presses are reported both through the input
+ layer and also as ACPI events through procfs (but not
+ through netlink). If it is set to 2, hot key presses
+ are reported only through the input layer.
+
+ This attribute is read-only in kernels 2.6.23 or later,
+ and read-write on earlier kernels.
+
+ May return -EPERM (write access locked out by module
+ parameter) or -EACCES (read-only).
+
input layer notes:
A Hot key is mapped to a single input layer EV_KEY event, possibly
@@ -393,21 +409,63 @@ unknown by the driver if the ThinkPad firmware triggered these events on
hot key press or release, but the firmware will do it for either one, not
both.
-If a key is mapped to KEY_RESERVED, it generates no input events at all,
-and it may generate a legacy thinkpad-acpi ACPI hotkey event.
-
+If a key is mapped to KEY_RESERVED, it generates no input events at all.
If a key is mapped to KEY_UNKNOWN, it generates an input event that
-includes an scan code, and it may also generate a legacy thinkpad-acpi
-ACPI hotkey event.
-
-If a key is mapped to anything else, it will only generate legacy
-thinkpad-acpi ACPI hotkey events if nobody has opened the input device.
+includes an scan code. If a key is mapped to anything else, it will
+generate input device EV_KEY events.
Non hot-key ACPI HKEY event map:
0x5001 Lid closed
0x5002 Lid opened
0x7000 Radio Switch may have changed state
+The above events are not propagated by the driver, except for legacy
+compatibility purposes when hotkey_report_mode is set to 1.
+
+Compatibility notes:
+
+ibm-acpi and thinkpad-acpi 0.15 (mainline kernels before 2.6.23) never
+supported the input layer, and sent events over the procfs ACPI event
+interface.
+
+To avoid sending duplicate events over the input layer and the ACPI
+event interface, thinkpad-acpi 0.16 implements a module parameter
+(hotkey_report_mode), and also a sysfs device attribute with the same
+name.
+
+Make no mistake here: userspace is expected to switch to using the input
+layer interface of thinkpad-acpi, together with the ACPI netlink event
+interface in kernels 2.6.23 and later, or with the ACPI procfs event
+interface in kernels 2.6.22 and earlier.
+
+If no hotkey_report_mode module parameter is specified (or it is set to
+zero), the driver defaults to mode 1 (see below), and on kernels 2.6.22
+and earlier, also allows one to change the hotkey_report_mode through
+sysfs. In kernels 2.6.23 and later, where the netlink ACPI event
+interface is available, hotkey_report_mode cannot be changed through
+sysfs (it is read-only).
+
+If the hotkey_report_mode module parameter is set to 1 or 2, it cannot
+be changed later through sysfs (any writes will return -EPERM to signal
+that hotkey_report_mode was locked. On 2.6.23 and later, where
+hotkey_report_mode cannot be changed at all, writes will return -EACES).
+
+hotkey_report_mode set to 1 makes the driver export through the procfs
+ACPI event interface all hot key presses (which are *also* sent to the
+input layer). This is a legacy compatibility behaviour, and it is also
+the default mode of operation for the driver.
+
+hotkey_report_mode set to 2 makes the driver filter out the hot key
+presses from the procfs ACPI event interface, so these events will only
+be sent through the input layer. Userspace that has been updated to use
+the thinkpad-acpi input layer interface should set hotkey_report_mode to
+2.
+
+Hot key press events are never sent to the ACPI netlink event interface.
+Really up-to-date userspace under kernel 2.6.23 and later is to use the
+netlink interface and the input layer interface, and don't bother at all
+with hotkey_report_mode.
+
Bluetooth
---------
diff --git a/Documentation/video4linux/cx2341x/fw-encoder-api.txt b/Documentation/video4linux/cx2341x/fw-encoder-api.txt
index 5dd3109a8b3..5a27af2ee1c 100644
--- a/Documentation/video4linux/cx2341x/fw-encoder-api.txt
+++ b/Documentation/video4linux/cx2341x/fw-encoder-api.txt
@@ -407,8 +407,10 @@ Description
u32 length; // Length of this frame
u32 offset_low; // Offset in the file of the
u32 offset_high; // start of this frame
- u32 mask1; // Bits 0-1 are the type mask:
+ u32 mask1; // Bits 0-2 are the type mask:
// 1=I, 2=P, 4=B
+ // 0=End of Program Index, other fields
+ // are invalid.
u32 pts; // The PTS of the frame
u32 mask2; // Bit 0 is bit 32 of the pts.
};
diff --git a/arch/arm/mach-realview/realview_eb.c b/arch/arm/mach-realview/realview_eb.c
index 3dba666151d..ecec2f85c4c 100644
--- a/arch/arm/mach-realview/realview_eb.c
+++ b/arch/arm/mach-realview/realview_eb.c
@@ -165,7 +165,7 @@ static void __init gic_init_irq(void)
#endif
gic_dist_init(0, __io_address(REALVIEW_GIC_DIST_BASE), 29);
gic_cpu_init(0, __io_address(REALVIEW_GIC_CPU_BASE));
-#ifdef CONFIG_REALVIEW_MPCORE
+#if defined(CONFIG_REALVIEW_MPCORE) && !defined(CONFIG_REALVIEW_MPCORE_REVB)
gic_dist_init(1, __io_address(REALVIEW_GIC1_DIST_BASE), 64);
gic_cpu_init(1, __io_address(REALVIEW_GIC1_CPU_BASE));
gic_cascade_irq(1, IRQ_EB_IRQ1);
diff --git a/arch/arm/vfp/vfpmodule.c b/arch/arm/vfp/vfpmodule.c
index 04ddab2bd87..eea3f50743d 100644
--- a/arch/arm/vfp/vfpmodule.c
+++ b/arch/arm/vfp/vfpmodule.c
@@ -323,6 +323,7 @@ static int __init vfp_init(void)
* we just need to read the VFPSID register.
*/
vfp_vector = vfp_testing_entry;
+ barrier();
vfpsid = fmrx(FPSID);
barrier();
vfp_vector = vfp_null_entry;
diff --git a/arch/blackfin/mach-common/pm.c b/arch/blackfin/mach-common/pm.c
index 1772d8d2c1a..b1030272220 100644
--- a/arch/blackfin/mach-common/pm.c
+++ b/arch/blackfin/mach-common/pm.c
@@ -158,10 +158,16 @@ static int bfin_pm_finish(suspend_state_t state)
return 0;
}
+static int bfin_pm_valid(suspend_state_t state)
+{
+ return (state == PM_SUSPEND_STANDBY);
+}
+
struct pm_ops bfin_pm_ops = {
.prepare = bfin_pm_prepare,
.enter = bfin_pm_enter,
.finish = bfin_pm_finish,
+ .valid = bfin_pm_valid,
};
static int __init bfin_pm_init(void)
diff --git a/arch/i386/xen/enlighten.c b/arch/i386/xen/enlighten.c
index f0c37511d8d..f01bfcd4bde 100644
--- a/arch/i386/xen/enlighten.c
+++ b/arch/i386/xen/enlighten.c
@@ -623,8 +623,8 @@ static unsigned long xen_read_cr2_direct(void)
static void xen_write_cr4(unsigned long cr4)
{
- /* never allow TSC to be disabled */
- native_write_cr4(cr4 & ~X86_CR4_TSD);
+ /* Just ignore cr4 changes; Xen doesn't allow us to do
+ anything anyway. */
}
static unsigned long xen_read_cr3(void)
diff --git a/arch/mips/dec/setup.c b/arch/mips/dec/setup.c
index b8a5e75ba0a..3e634f2f544 100644
--- a/arch/mips/dec/setup.c
+++ b/arch/mips/dec/setup.c
@@ -55,7 +55,7 @@ EXPORT_SYMBOL(dec_kn_slot_size);
int dec_tc_bus;
-spinlock_t ioasic_ssr_lock;
+DEFINE_SPINLOCK(ioasic_ssr_lock);
volatile u32 *ioasic_base;
diff --git a/arch/mips/kernel/cpu-bugs64.c b/arch/mips/kernel/cpu-bugs64.c
index ac04f0adc40..6648fde20b9 100644
--- a/arch/mips/kernel/cpu-bugs64.c
+++ b/arch/mips/kernel/cpu-bugs64.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003, 2004 Maciej W. Rozycki
+ * Copyright (C) 2003, 2004, 2007 Maciej W. Rozycki
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -29,7 +29,7 @@ static inline void align_mod(const int align, const int mod)
".endr\n\t"
".set pop"
:
- : "rn" (align), "rn" (mod));
+ : GCC_IMM_ASM (align), GCC_IMM_ASM (mod));
}
static inline void mult_sh_align_mod(long *v1, long *v2, long *w,
diff --git a/arch/mips/kernel/cpu-probe.c b/arch/mips/kernel/cpu-probe.c
index 06448a9656d..3e004161ebd 100644
--- a/arch/mips/kernel/cpu-probe.c
+++ b/arch/mips/kernel/cpu-probe.c
@@ -199,7 +199,14 @@ static inline void check_wait(void)
if ((c->processor_id & 0xff) <= 0x64)
break;
- cpu_wait = r4k_wait;
+ /*
+ * Another rev is incremeting c0_count at a reduced clock
+ * rate while in WAIT mode. So we basically have the choice
+ * between using the cp0 timer as clocksource or avoiding
+ * the WAIT instruction. Until more details are known,
+ * disable the use of WAIT for 20Kc entirely.
+ cpu_wait = r4k_wait;
+ */
break;
case CPU_RM9000:
if ((c->processor_id & 0x00ff) >= 0x40)
diff --git a/arch/mips/kernel/rtlx.c b/arch/mips/kernel/rtlx.c
index aab89e97abb..1ba00c15505 100644
--- a/arch/mips/kernel/rtlx.c
+++ b/arch/mips/kernel/rtlx.c
@@ -56,8 +56,6 @@ static struct chan_waitqueues {
struct mutex mutex;
} channel_wqs[RTLX_CHANNELS];
-static struct irqaction irq;
-static int irq_num;
static struct vpe_notifications notify;
static int sp_stopping = 0;
@@ -111,7 +109,7 @@ static void __used dump_rtlx(void)
static int rtlx_init(struct rtlx_info *rtlxi)
{
if (rtlxi->id != RTLX_ID) {
- printk(KERN_ERR "no valid RTLX id at 0x%p 0x%x\n", rtlxi, rtlxi->id);
+ printk(KERN_ERR "no valid RTLX id at 0x%p 0x%lx\n", rtlxi, rtlxi->id);
return -ENOEXEC;
}
diff --git a/arch/mips/kernel/scall64-n32.S b/arch/mips/kernel/scall64-n32.S
index 53d7a977193..118be24224f 100644
--- a/arch/mips/kernel/scall64-n32.S
+++ b/arch/mips/kernel/scall64-n32.S
@@ -375,7 +375,7 @@ EXPORT(sysn32_call_table)
PTR sys_mkdirat
PTR sys_mknodat
PTR sys_fchownat
- PTR sys_futimesat /* 6255 */
+ PTR compat_sys_futimesat /* 6255 */
PTR sys_newfstatat
PTR sys_unlinkat
PTR sys_renameat
diff --git a/arch/mips/kernel/time.c b/arch/mips/kernel/time.c
index d48d1d5bea0..9a5596bf857 100644
--- a/arch/mips/kernel/time.c
+++ b/arch/mips/kernel/time.c
@@ -16,6 +16,7 @@
#include <linux/init.h>
#include <linux/sched.h>
#include <linux/param.h>
+#include <linux/profile.h>
#include <linux/time.h>
#include <linux/timex.h>
#include <linux/smp.h>
diff --git a/arch/mips/mips-boards/malta/malta_int.c b/arch/mips/mips-boards/malta/malta_int.c
index 97aeb8c4e60..b73f21823c5 100644
--- a/arch/mips/mips-boards/malta/malta_int.c
+++ b/arch/mips/mips-boards/malta/malta_int.c
@@ -256,7 +256,7 @@ asmlinkage void plat_irq_dispatch(void)
if (irq == MIPSCPU_INT_I8259A)
malta_hw0_irqdispatch();
- else if (irq > 0)
+ else if (irq >= 0)
do_IRQ(MIPS_CPU_IRQ_BASE + irq);
else
spurious_interrupt();
diff --git a/arch/mips/mm/tlbex.c b/arch/mips/mm/tlbex.c
index 9cb39644b6f..6c425b05244 100644
--- a/arch/mips/mm/tlbex.c
+++ b/arch/mips/mm/tlbex.c
@@ -58,6 +58,21 @@ static __init int __maybe_unused r10000_llsc_war(void)
}
/*
+ * Found by experiment: At least some revisions of the 4kc throw under
+ * some circumstances a machine check exception, triggered by invalid
+ * values in the index register. Delaying the tlbp instruction until
+ * after the next branch, plus adding an additional nop in front of
+ * tlbwi/tlbwr avoids the invalid index register values. Nobody knows
+ * why; it's not an issue caused by the core RTL.
+ *
+ */
+static __init int __attribute__((unused)) m4kc_tlbp_war(void)
+{
+ return (current_cpu_data.processor_id & 0xffff00) ==
+ (PRID_COMP_MIPS | PRID_IMP_4KC);
+}
+
+/*
* A little micro-assembler, intended for TLB refill handler
* synthesizing. It is intentionally kept simple, does only support
* a subset of instructions, and does not try to hide pipeline effects
@@ -894,6 +909,8 @@ static __init void build_tlb_write_entry(u32 **p, struct label **l,
case CPU_20KC:
case CPU_25KF:
case CPU_LOONGSON2:
+ if (m4kc_tlbp_war())
+ i_nop(p);
tlbw(p);
break;
@@ -1705,7 +1722,8 @@ build_r4000_tlbchange_handler_head(u32 **p, struct label **l,
l_smp_pgtable_change(l, *p);
# endif
iPTE_LW(p, l, pte, ptr); /* get even pte */
- build_tlb_probe_entry(p);
+ if (!m4kc_tlbp_war())
+ build_tlb_probe_entry(p);
}
static void __init
@@ -1747,6 +1765,8 @@ static void __init build_r4000_tlb_load_handler(void)
build_r4000_tlbchange_handler_head(&p, &l, &r, K0, K1);
build_pte_present(&p, &l, &r, K0, K1, label_nopage_tlbl);
+ if (m4kc_tlbp_war())
+ build_tlb_probe_entry(&p);
build_make_valid(&p, &r, K0, K1);
build_r4000_tlbchange_handler_tail(&p, &l, &r, K0, K1);
@@ -1781,6 +1801,8 @@ static void __init build_r4000_tlb_store_handler(void)
build_r4000_tlbchange_handler_head(&p, &l, &r, K0, K1);
build_pte_writable(&p, &l, &r, K0, K1, label_nopage_tlbs);
+ if (m4kc_tlbp_war())
+ build_tlb_probe_entry(&p);
build_make_write(&p, &r, K0, K1);
build_r4000_tlbchange_handler_tail(&p, &l, &r, K0, K1);
@@ -1815,6 +1837,8 @@ static void __init build_r4000_tlb_modify_handler(void)
build_r4000_tlbchange_handler_head(&p, &l, &r, K0, K1);
build_pte_modifiable(&p, &l, &r, K0, K1, label_nopage_tlbm);
+ if (m4kc_tlbp_war())
+ build_tlb_probe_entry(&p);
/* Present and writable bits set, set accessed and dirty bits. */
build_make_write(&p, &r, K0, K1);
build_r4000_tlbchange_handler_tail(&p, &l, &r, K0, K1);
diff --git a/arch/powerpc/kernel/time.c b/arch/powerpc/kernel/time.c
index b5944d8e380..d95e68c0a6b 100644
--- a/arch/powerpc/kernel/time.c
+++ b/arch/powerpc/kernel/time.c
@@ -238,7 +238,7 @@ static void snapshot_tb_and_purr(void *data)
struct cpu_purr_data *p = &__get_cpu_var(cpu_purr_data);
local_irq_save(flags);
- p->tb = mftb();
+ p->tb = get_tb_or_rtc();
p->purr = mfspr(SPRN_PURR);
wmb();
p->initialized = 1;
@@ -316,7 +316,7 @@ static void snapshot_purr(void)
*/
void snapshot_timebase(void)
{
- __get_cpu_var(last_jiffy) = get_tb();
+ __get_cpu_var(last_jiffy) = get_tb_or_rtc();
snapshot_purr();
}
@@ -683,6 +683,8 @@ void timer_interrupt(struct pt_regs * regs)
write_seqlock(&xtime_lock);
tb_next_jiffy = tb_last_jiffy + tb_ticks_per_jiffy;
+ if (__USE_RTC() && tb_next_jiffy >= 1000000000)
+ tb_next_jiffy -= 1000000000;
if (per_cpu(last_jiffy, cpu) >= tb_next_jiffy) {
tb_last_jiffy = tb_next_jiffy;
do_timer(1);
@@ -976,7 +978,7 @@ void __init time_init(void)
tb_to_ns_scale = scale;
tb_to_ns_shift = shift;
/* Save the current timebase to pretty up CONFIG_PRINTK_TIME */
- boot_tb = get_tb();
+ boot_tb = get_tb_or_rtc();
tm = get_boot_time();
diff --git a/arch/powerpc/kernel/vdso.c b/arch/powerpc/kernel/vdso.c
index cef01e4e898..213fa31ac53 100644
--- a/arch/powerpc/kernel/vdso.c
+++ b/arch/powerpc/kernel/vdso.c
@@ -98,6 +98,18 @@ static struct vdso_patch_def vdso_patches[] = {
CPU_FTR_USE_TB, 0,
"__kernel_gettimeofday", NULL
},
+ {
+ CPU_FTR_USE_TB, 0,
+ "__kernel_clock_gettime", NULL
+ },
+ {
+ CPU_FTR_USE_TB, 0,
+ "__kernel_clock_getres", NULL
+ },
+ {
+ CPU_FTR_USE_TB, 0,
+ "__kernel_get_tbfreq", NULL
+ },
};
/*
diff --git a/arch/powerpc/platforms/cell/spufs/sched.c b/arch/powerpc/platforms/cell/spufs/sched.c
index 17806e001e5..4d257b3f933 100644
--- a/arch/powerpc/platforms/cell/spufs/sched.c
+++ b/arch/powerpc/platforms/cell/spufs/sched.c
@@ -594,7 +594,7 @@ static struct spu *find_victim(struct spu_context *ctx)
list_for_each_entry(spu, &cbe_spu_info[node].spus, cbe_list) {
struct spu_context *tmp = spu->ctx;
- if (tmp->prio > ctx->prio &&
+ if (tmp && tmp->prio > ctx->prio &&
(!victim || tmp->prio > victim->prio))
victim = spu->ctx;
}
@@ -626,9 +626,9 @@ static struct spu *find_victim(struct spu_context *ctx)
mutex_lock(&cbe_spu_info[node].list_mutex);
cbe_spu_info[node].nr_active--;
+ spu_unbind_context(spu, victim);
mutex_unlock(&cbe_spu_info[node].list_mutex);
- spu_unbind_context(spu, victim);
victim->stats.invol_ctx_switch++;
spu->stats.invol_ctx_switch++;
mutex_unlock(&victim->state_mutex);
diff --git a/arch/sparc64/defconfig b/arch/sparc64/defconfig
index 68338a601f7..7d07297db87 100644
--- a/arch/sparc64/defconfig
+++ b/arch/sparc64/defconfig
@@ -1,7 +1,7 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.23-rc1
-# Sun Jul 22 19:24:37 2007
+# Linux kernel version: 2.6.23-rc6
+# Sun Sep 16 09:52:11 2007
#
CONFIG_SPARC=y
CONFIG_SPARC64=y
@@ -32,15 +32,11 @@ CONFIG_HZ=100
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
#
-# Code maturity level options
+# General setup
#
CONFIG_EXPERIMENTAL=y
CONFIG_BROKEN_ON_SMP=y
CONFIG_INIT_ENV_ARG_LIMIT=32
-
-#
-# General setup
-#
CONFIG_LOCALVERSION=""
# CONFIG_LOCALVERSION_AUTO is not set
CONFIG_SWAP=y
@@ -555,6 +551,7 @@ CONFIG_E1000_NAPI=y
# CONFIG_SIS190 is not set
# CONFIG_SKGE is not set
# CONFIG_SKY2 is not set
+# CONFIG_SK98LIN is not set
# CONFIG_VIA_VELOCITY is not set
CONFIG_TIGON3=m
CONFIG_BNX2=m
@@ -809,6 +806,7 @@ CONFIG_HWMON=y
# CONFIG_SENSORS_SMSC47M1 is not set
# CONFIG_SENSORS_SMSC47M192 is not set
# CONFIG_SENSORS_SMSC47B397 is not set
+# CONFIG_SENSORS_THMC50 is not set
# CONFIG_SENSORS_VIA686A is not set
# CONFIG_SENSORS_VT1211 is not set
# CONFIG_SENSORS_VT8231 is not set
@@ -1162,10 +1160,6 @@ CONFIG_USB_STORAGE=m
# CONFIG_MMC is not set
# CONFIG_NEW_LEDS is not set
# CONFIG_INFINIBAND is not set
-
-#
-# Real Time Clock
-#
# CONFIG_RTC_CLASS is not set
#
diff --git a/arch/sparc64/kernel/head.S b/arch/sparc64/kernel/head.S
index 63144ad476f..c4147ad8677 100644
--- a/arch/sparc64/kernel/head.S
+++ b/arch/sparc64/kernel/head.S
@@ -98,7 +98,7 @@ sparc64_boot:
.globl prom_boot_mapped_pc, prom_boot_mapping_mode
.globl prom_boot_mapping_phys_high, prom_boot_mapping_phys_low
.globl prom_compatible_name, prom_cpu_path, prom_cpu_compatible
- .globl is_sun4v, sun4v_chip_type
+ .globl is_sun4v, sun4v_chip_type, prom_set_trap_table_name
prom_peer_name:
.asciz "peer"
prom_compatible_name:
@@ -121,6 +121,8 @@ prom_map_name:
.asciz "map"
prom_unmap_name:
.asciz "unmap"
+prom_set_trap_table_name:
+ .asciz "SUNW,set-trap-table"
prom_sun4v_name:
.asciz "sun4v"
prom_niagara_prefix:
@@ -691,15 +693,38 @@ setup_trap_table:
sethi %hi(kern_base), %g3
ldx [%g3 + %lo(kern_base)], %g3
add %g2, %g3, %o1
+ sethi %hi(sparc64_ttable_tl0), %o0
- call prom_set_trap_table_sun4v
- sethi %hi(sparc64_ttable_tl0), %o0
+ set prom_set_trap_table_name, %g2
+ stx %g2, [%sp + 2047 + 128 + 0x00]
+ mov 2, %g2
+ stx %g2, [%sp + 2047 + 128 + 0x08]
+ mov 0, %g2
+ stx %g2, [%sp + 2047 + 128 + 0x10]
+ stx %o0, [%sp + 2047 + 128 + 0x18]
+ stx %o1, [%sp + 2047 + 128 + 0x20]
+ sethi %hi(p1275buf), %g2
+ or %g2, %lo(p1275buf), %g2
+ ldx [%g2 + 0x08], %o1
+ call %o1
+ add %sp, (2047 + 128), %o0
ba,pt %xcc, 2f
nop
-1: call prom_set_trap_table
- sethi %hi(sparc64_ttable_tl0), %o0
+1: sethi %hi(sparc64_ttable_tl0), %o0
+ set prom_set_trap_table_name, %g2
+ stx %g2, [%sp + 2047 + 128 + 0x00]
+ mov 1, %g2
+ stx %g2, [%sp + 2047 + 128 + 0x08]
+ mov 0, %g2
+ stx %g2, [%sp + 2047 + 128 + 0x10]
+ stx %o0, [%sp + 2047 + 128 + 0x18]
+ sethi %hi(p1275buf), %g2
+ or %g2, %lo(p1275buf), %g2
+ ldx [%g2 + 0x08], %o1
+ call %o1
+ add %sp, (2047 + 128), %o0
/* Start using proper page size encodings in ctx register. */
2: sethi %hi(sparc64_kern_pri_context), %g3
diff --git a/arch/sparc64/kernel/mdesc.c b/arch/sparc64/kernel/mdesc.c
index 9f22e4ff601..856659bb131 100644
--- a/arch/sparc64/kernel/mdesc.c
+++ b/arch/sparc64/kernel/mdesc.c
@@ -777,8 +777,12 @@ void __devinit mdesc_fill_in_cpu_data(cpumask_t mask)
cpuid = *id;
#ifdef CONFIG_SMP
- if (cpuid >= NR_CPUS)
+ if (cpuid >= NR_CPUS) {
+ printk(KERN_WARNING "Ignoring CPU %d which is "
+ ">= NR_CPUS (%d)\n",
+ cpuid, NR_CPUS);
continue;
+ }
if (!cpu_isset(cpuid, mask))
continue;
#else
diff --git a/arch/sparc64/kernel/prom.c b/arch/sparc64/kernel/prom.c
index d1a78c976ce..0614dff63d7 100644
--- a/arch/sparc64/kernel/prom.c
+++ b/arch/sparc64/kernel/prom.c
@@ -1583,8 +1583,12 @@ static void __init of_fill_in_cpu_data(void)
ncpus_probed++;
#ifdef CONFIG_SMP
- if (cpuid >= NR_CPUS)
+ if (cpuid >= NR_CPUS) {
+ printk(KERN_WARNING "Ignoring CPU %d which is "
+ ">= NR_CPUS (%d)\n",
+ cpuid, NR_CPUS);
continue;
+ }
#else
/* On uniprocessor we only want the values for the
* real physical cpu the kernel booted onto, however
diff --git a/arch/sparc64/kernel/trampoline.S b/arch/sparc64/kernel/trampoline.S
index 9533a25ce5d..04e81dda13d 100644
--- a/arch/sparc64/kernel/trampoline.S
+++ b/arch/sparc64/kernel/trampoline.S
@@ -345,7 +345,7 @@ after_lock_tlb:
sethi %hi(tramp_stack), %g1
or %g1, %lo(tramp_stack), %g1
add %g1, TRAMP_STACK_SIZE, %g1
- sub %g1, STACKFRAME_SZ + STACK_BIAS, %sp
+ sub %g1, STACKFRAME_SZ + STACK_BIAS + 256, %sp
mov 0, %fp
/* Put garbage in these registers to trap any access to them. */
@@ -411,15 +411,38 @@ after_lock_tlb:
sethi %hi(kern_base), %g3
ldx [%g3 + %lo(kern_base)], %g3
add %g2, %g3, %o1
+ sethi %hi(sparc64_ttable_tl0), %o0
- call prom_set_trap_table_sun4v
- sethi %hi(sparc64_ttable_tl0), %o0
+ set prom_set_trap_table_name, %g2
+ stx %g2, [%sp + 2047 + 128 + 0x00]
+ mov 2, %g2
+ stx %g2, [%sp + 2047 + 128 + 0x08]
+ mov 0, %g2
+ stx %g2, [%sp + 2047 + 128 + 0x10]
+ stx %o0, [%sp + 2047 + 128 + 0x18]
+ stx %o1, [%sp + 2047 + 128 + 0x20]
+ sethi %hi(p1275buf), %g2
+ or %g2, %lo(p1275buf), %g2
+ ldx [%g2 + 0x08], %o1
+ call %o1
+ add %sp, (2047 + 128), %o0
ba,pt %xcc, 2f
nop
-1: call prom_set_trap_table
- sethi %hi(sparc64_ttable_tl0), %o0
+1: sethi %hi(sparc64_ttable_tl0), %o0
+ set prom_set_trap_table_name, %g2
+ stx %g2, [%sp + 2047 + 128 + 0x00]
+ mov 1, %g2
+ stx %g2, [%sp + 2047 + 128 + 0x08]
+ mov 0, %g2
+ stx %g2, [%sp + 2047 + 128 + 0x10]
+ stx %o0, [%sp + 2047 + 128 + 0x18]
+ sethi %hi(p1275buf), %g2
+ or %g2, %lo(p1275buf), %g2
+ ldx [%g2 + 0x08], %o1
+ call %o1
+ add %sp, (2047 + 128), %o0
2: ldx [%l0], %g6
ldx [%g6 + TI_TASK], %g4
diff --git a/arch/sparc64/prom/misc.c b/arch/sparc64/prom/misc.c
index 68c83ad04ad..bbec7522826 100644
--- a/arch/sparc64/prom/misc.c
+++ b/arch/sparc64/prom/misc.c
@@ -143,22 +143,6 @@ unsigned char prom_get_idprom(char *idbuf, int num_bytes)
return 0xff;
}
-/* Install Linux trap table so PROM uses that instead of its own. */
-void prom_set_trap_table(unsigned long tba)
-{
- p1275_cmd("SUNW,set-trap-table",
- (P1275_ARG(0, P1275_ARG_IN_64B) |
- P1275_INOUT(1, 0)), tba);
-}
-
-void prom_set_trap_table_sun4v(unsigned long tba, unsigned long mmfsa)
-{
- p1275_cmd("SUNW,set-trap-table",
- (P1275_ARG(0, P1275_ARG_IN_64B) |
- P1275_ARG(1, P1275_ARG_IN_64B) |
- P1275_INOUT(2, 0)), tba, mmfsa);
-}
-
int prom_get_mmu_ihandle(void)
{
int node, ret;
diff --git a/arch/um/include/kern_util.h b/arch/um/include/kern_util.h
index 8d7f7c1cb9c..6c2be26f1d7 100644
--- a/arch/um/include/kern_util.h
+++ b/arch/um/include/kern_util.h
@@ -117,7 +117,7 @@ extern void sigio_handler(int sig, union uml_pt_regs *regs);
extern void copy_sc(union uml_pt_regs *regs, void *from);
-unsigned long to_irq_stack(int sig, unsigned long *mask_out);
+extern unsigned long to_irq_stack(unsigned long *mask_out);
unsigned long from_irq_stack(int nested);
#endif
diff --git a/arch/um/kernel/irq.c b/arch/um/kernel/irq.c
index 9870febdbea..cf0dd9cf8c4 100644
--- a/arch/um/kernel/irq.c
+++ b/arch/um/kernel/irq.c
@@ -518,13 +518,13 @@ int init_aio_irq(int irq, char *name, irq_handler_t handler)
static unsigned long pending_mask;
-unsigned long to_irq_stack(int sig, unsigned long *mask_out)
+unsigned long to_irq_stack(unsigned long *mask_out)
{
struct thread_info *ti;
unsigned long mask, old;
int nested;
- mask = xchg(&pending_mask, 1 << sig);
+ mask = xchg(&pending_mask, *mask_out);
if(mask != 0){
/* If any interrupts come in at this point, we want to
* make sure that their bits aren't lost by our
@@ -534,7 +534,7 @@ unsigned long to_irq_stack(int sig, unsigned long *mask_out)
* and pending_mask contains a bit for each interrupt
* that came in.
*/
- old = 1 << sig;
+ old = *mask_out;
do {
old |= mask;
mask = xchg(&pending_mask, old);
@@ -550,6 +550,7 @@ unsigned long to_irq_stack(int sig, unsigned long *mask_out)
task = cpu_tasks[ti->cpu].task;
tti = task_thread_info(task);
+
*ti = *tti;
ti->real_thread = tti;
task->stack = ti;
diff --git a/arch/um/os-Linux/file.c b/arch/um/os-Linux/file.c
index 6f92f732d25..c3ecc2a84e0 100644
--- a/arch/um/os-Linux/file.c
+++ b/arch/um/os-Linux/file.c
@@ -320,7 +320,8 @@ int os_file_size(char *file, unsigned long long *size_out)
}
if(S_ISBLK(buf.ust_mode)){
- int fd, blocks;
+ int fd;
+ long blocks;
fd = os_open_file(file, of_read(OPENFLAGS()), 0);
if(fd < 0){
diff --git a/arch/um/os-Linux/signal.c b/arch/um/os-Linux/signal.c
index 18e5c8b67eb..b98f7ea2d2f 100644
--- a/arch/um/os-Linux/signal.c
+++ b/arch/um/os-Linux/signal.c
@@ -119,7 +119,7 @@ void (*handlers[_NSIG])(int sig, struct sigcontext *sc);
void handle_signal(int sig, struct sigcontext *sc)
{
- unsigned long pending = 0;
+ unsigned long pending = 1UL << sig;
do {
int nested, bail;
@@ -134,7 +134,7 @@ void handle_signal(int sig, struct sigcontext *sc)
* have to return, and the upper handler will deal
* with this interrupt.
*/
- bail = to_irq_stack(sig, &pending);
+ bail = to_irq_stack(&pending);
if(bail)
return;
diff --git a/arch/x86_64/mm/fault.c b/arch/x86_64/mm/fault.c
index 327c9f2fa62..54816adb8e9 100644
--- a/arch/x86_64/mm/fault.c
+++ b/arch/x86_64/mm/fault.c
@@ -374,6 +374,13 @@ asmlinkage void __kprobes do_page_fault(struct pt_regs *regs,
if (unlikely(in_atomic() || !mm))
goto bad_area_nosemaphore;
+ /*
+ * User-mode registers count as a user access even for any
+ * potential system fault or CPU buglet.
+ */
+ if (user_mode_vm(regs))
+ error_code |= PF_USER;
+
again:
/* When running in the kernel we expect faults to occur only to
* addresses in user space. All other faults represent errors in the
diff --git a/arch/xtensa/Makefile b/arch/xtensa/Makefile
index 95f836db38f..acf05be2492 100644
--- a/arch/xtensa/Makefile
+++ b/arch/xtensa/Makefile
@@ -27,7 +27,12 @@ platform-$(CONFIG_XTENSA_PLATFORM_ISS) := iss
PLATFORM = $(platform-y)
export PLATFORM
-CFLAGS += -pipe -mlongcalls
+# temporarily until string.h is fixed
+cflags-y += -ffreestanding
+
+cflags-y += -pipe -mlongcalls
+
+CFLAGS += $(cflags-y)
KBUILD_DEFCONFIG := iss_defconfig
diff --git a/arch/xtensa/kernel/Makefile b/arch/xtensa/kernel/Makefile
index 71f733c4f66..f582d6a24ec 100644
--- a/arch/xtensa/kernel/Makefile
+++ b/arch/xtensa/kernel/Makefile
@@ -7,7 +7,7 @@ extra-y := head.o vmlinux.lds
obj-y := align.o entry.o irq.o coprocessor.o process.o ptrace.o semaphore.o \
setup.o signal.o syscall.o time.o traps.o vectors.o platform.o \
- pci-dma.o
+ pci-dma.o init_task.o io.o
## windowspill.o
diff --git a/arch/xtensa/kernel/asm-offsets.c b/arch/xtensa/kernel/asm-offsets.c
index d0323cd6a2e..d5ffe7b6443 100644
--- a/arch/xtensa/kernel/asm-offsets.c
+++ b/arch/xtensa/kernel/asm-offsets.c
@@ -18,12 +18,13 @@
#include <linux/stddef.h>
#include <linux/thread_info.h>
#include <linux/ptrace.h>
+#include <linux/mm.h>
+
#include <asm/ptrace.h>
#include <asm/processor.h>
#include <asm/uaccess.h>
#define DEFINE(sym, val) asm volatile("\n->" #sym " %0 " #val : : "i" (val))
-#define BLANK() asm volatile("\n->" : : )
int main(void)
{
@@ -63,7 +64,6 @@ int main(void)
DEFINE(PT_SIZE, sizeof(struct pt_regs));
DEFINE(PT_AREG_END, offsetof (struct pt_regs, areg[XCHAL_NUM_AREGS]));
DEFINE(PT_USER_SIZE, offsetof(struct pt_regs, areg[XCHAL_NUM_AREGS]));
- BLANK();
/* struct task_struct */
DEFINE(TASK_PTRACE, offsetof (struct task_struct, ptrace));
@@ -73,27 +73,26 @@ int main(void)
DEFINE(TASK_THREAD, offsetof (struct task_struct, thread));
DEFINE(TASK_THREAD_INFO, offsetof (struct task_struct, stack));
DEFINE(TASK_STRUCT_SIZE, sizeof (struct task_struct));
- BLANK();
/* struct thread_info (offset from start_struct) */
DEFINE(THREAD_RA, offsetof (struct task_struct, thread.ra));
DEFINE(THREAD_SP, offsetof (struct task_struct, thread.sp));
DEFINE(THREAD_CP_SAVE, offsetof (struct task_struct, thread.cp_save));
DEFINE(THREAD_CURRENT_DS, offsetof (struct task_struct, thread.current_ds));
- BLANK();
/* struct mm_struct */
DEFINE(MM_USERS, offsetof(struct mm_struct, mm_users));
DEFINE(MM_PGD, offsetof (struct mm_struct, pgd));
DEFINE(MM_CONTEXT, offsetof (struct mm_struct, context));
- BLANK();
- DEFINE(PT_SINGLESTEP_BIT, PT_SINGLESTEP_BIT);
+
+ /* struct page */
+ DEFINE(PAGE_FLAGS, offsetof(struct page, flags));
/* constants */
DEFINE(_CLONE_VM, CLONE_VM);
DEFINE(_CLONE_UNTRACED, CLONE_UNTRACED);
+ DEFINE(PG_ARCH_1, PG_arch_1);
return 0;
}
-
diff --git a/arch/xtensa/kernel/entry.S b/arch/xtensa/kernel/entry.S
index 8dc7a2c26ff..91a689eca43 100644
--- a/arch/xtensa/kernel/entry.S
+++ b/arch/xtensa/kernel/entry.S
@@ -7,7 +7,7 @@
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
- * Copyright (C) 2004-2005 by Tensilica Inc.
+ * Copyright (C) 2004-2007 by Tensilica Inc.
*
* Chris Zankel <chris@zankel.net>
*
@@ -169,7 +169,7 @@ _user_exception:
* We have to save all registers up to the first '1' from
* the right, except the current frame (bit 0).
* Assume a2 is: 001001000110001
- * All regiser frames starting from the top fiel to the marked '1'
+ * All register frames starting from the top field to the marked '1'
* must be saved.
*/
@@ -1572,10 +1572,12 @@ ENTRY(fast_second_level_miss)
l32i a0, a1, TASK_MM # tsk->mm
beqz a0, 9f
-8: rsr a1, EXCVADDR # fault address
- _PGD_OFFSET(a0, a1, a1)
+
+ /* We deliberately destroy a3 that holds the exception table. */
+
+8: rsr a3, EXCVADDR # fault address
+ _PGD_OFFSET(a0, a3, a1)
l32i a0, a0, 0 # read pmdval
- //beqi a0, _PAGE_USER, 2f
beqz a0, 2f
/* Read ptevaddr and convert to top of page-table page.
@@ -1588,7 +1590,7 @@ ENTRY(fast_second_level_miss)
* The messy computation for 'pteval' above really simplifies
* into the following:
*
- * pteval = ((pmdval - PAGE_OFFSET) & PAGE_MASK) | PAGE_KERNEL
+ * pteval = ((pmdval - PAGE_OFFSET) & PAGE_MASK) | PAGE_DIRECTORY
*/
movi a1, -PAGE_OFFSET
@@ -1596,20 +1598,34 @@ ENTRY(fast_second_level_miss)
extui a1, a0, 0, PAGE_SHIFT # ... & PAGE_MASK
xor a0, a0, a1
-
- movi a1, PAGE_DIRECTORY
+ movi a1, _PAGE_DIRECTORY
or a0, a0, a1 # ... | PAGE_DIRECTORY
+ /*
+ * We utilize all three wired-ways (7-9) to hold pmd translations.
+ * Memory regions are mapped to the DTLBs according to bits 28 and 29.
+ * This allows to map the three most common regions to three different
+ * DTLBs:
+ * 0,1 -> way 7 program (0040.0000) and virtual (c000.0000)
+ * 2 -> way 8 shared libaries (2000.0000)
+ * 3 -> way 0 stack (3000.0000)
+ */
+
+ extui a3, a3, 28, 2 # addr. bit 28 and 29 0,1,2,3
rsr a1, PTEVADDR
+ addx2 a3, a3, a3 # -> 0,3,6,9
srli a1, a1, PAGE_SHIFT
+ extui a3, a3, 2, 2 # -> 0,0,1,2
slli a1, a1, PAGE_SHIFT # ptevaddr & PAGE_MASK
- addi a1, a1, DTLB_WAY_PGD # ... + way_number
+ addi a3, a3, DTLB_WAY_PGD
+ add a1, a1, a3 # ... + way_number
- wdtlb a0, a1
+3: wdtlb a0, a1
dsync
/* Exit critical section. */
+4: movi a3, exc_table # restore a3
movi a0, 0
s32i a0, a3, EXC_TABLE_FIXUP
@@ -1636,8 +1652,76 @@ ENTRY(fast_second_level_miss)
9: l32i a0, a1, TASK_ACTIVE_MM # unlikely case mm == 0
j 8b
+#if (DCACHE_WAY_SIZE > PAGE_SIZE)
+
+2: /* Special case for cache aliasing.
+ * We (should) only get here if a clear_user_page, copy_user_page
+ * or the aliased cache flush functions got preemptively interrupted
+ * by another task. Re-establish temporary mapping to the
+ * TLBTEMP_BASE areas.
+ */
+
+ /* We shouldn't be in a double exception */
+
+ l32i a0, a2, PT_DEPC
+ bgeui a0, VALID_DOUBLE_EXCEPTION_ADDRESS, 2f
+
+ /* Make sure the exception originated in the special functions */
+
+ movi a0, __tlbtemp_mapping_start
+ rsr a3, EPC_1
+ bltu a3, a0, 2f
+ movi a0, __tlbtemp_mapping_end
+ bgeu a3, a0, 2f
+
+ /* Check if excvaddr was in one of the TLBTEMP_BASE areas. */
+
+ movi a3, TLBTEMP_BASE_1
+ rsr a0, EXCVADDR
+ bltu a0, a3, 2f
+
+ addi a1, a0, -(2 << (DCACHE_ALIAS_ORDER + PAGE_SHIFT))
+ bgeu a1, a3, 2f
+
+ /* Check if we have to restore an ITLB mapping. */
+
+ movi a1, __tlbtemp_mapping_itlb
+ rsr a3, EPC_1
+ sub a3, a3, a1
+
+ /* Calculate VPN */
+
+ movi a1, PAGE_MASK
+ and a1, a1, a0
+
+ /* Jump for ITLB entry */
+
+ bgez a3, 1f
+
+ /* We can use up to two TLBTEMP areas, one for src and one for dst. */
+
+ extui a3, a0, PAGE_SHIFT + DCACHE_ALIAS_ORDER, 1
+ add a1, a3, a1
+
+ /* PPN is in a6 for the first TLBTEMP area and in a7 for the second. */
+
+ mov a0, a6
+ movnez a0, a7, a3
+ j 3b
+
+ /* ITLB entry. We only use dst in a6. */
+
+1: witlb a6, a1
+ isync
+ j 4b
+
+
+#endif // DCACHE_WAY_SIZE > PAGE_SIZE
+
+
2: /* Invalid PGD, default exception handling */
+ movi a3, exc_table
rsr a1, DEPC
xsr a3, EXCSAVE_1
s32i a1, a2, PT_AREG2
@@ -1682,15 +1766,15 @@ ENTRY(fast_store_prohibited)
8: rsr a1, EXCVADDR # fault address
_PGD_OFFSET(a0, a1, a4)
l32i a0, a0, 0
- //beqi a0, _PAGE_USER, 2f # FIXME use _PAGE_INVALID
beqz a0, 2f
+ /* Note that we assume _PAGE_WRITABLE_BIT is only set if pte is valid.*/
+
_PTE_OFFSET(a0, a1, a4)
l32i a4, a0, 0 # read pteval
- movi a1, _PAGE_VALID | _PAGE_RW
- bnall a4, a1, 2f
+ bbci.l a4, _PAGE_WRITABLE_BIT, 2f
- movi a1, _PAGE_ACCESSED | _PAGE_DIRTY | _PAGE_WRENABLE
+ movi a1, _PAGE_ACCESSED | _PAGE_DIRTY | _PAGE_HW_WRITE
or a4, a4, a1
rsr a1, EXCVADDR
s32i a4, a0, 0
@@ -1700,10 +1784,7 @@ ENTRY(fast_store_prohibited)
dhwb a0, 0
#endif
pdtlb a0, a1
- beqz a0, 1f
- idtlb a0 // FIXME do we need this?
wdtlb a4, a0
-1:
/* Exit critical section. */
diff --git a/arch/xtensa/kernel/init_task.c b/arch/xtensa/kernel/init_task.c
new file mode 100644
index 00000000000..021b4f46ff9
--- /dev/null
+++ b/arch/xtensa/kernel/init_task.c
@@ -0,0 +1,38 @@
+/*
+ * arch/xtensa/kernel/init_task.c
+ *
+ * Xtensa Processor version.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2007 Tensilica Inc.
+ *
+ * Chris Zankel <chris@zankel.net>
+ */
+
+#include <linux/mm.h>
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/init_task.h>
+#include <linux/module.h>
+#include <linux/mqueue.h>
+
+#include <asm/uaccess.h>
+
+static struct fs_struct init_fs = INIT_FS;
+static struct files_struct init_files = INIT_FILES;
+static struct signal_struct init_signals = INIT_SIGNALS(init_signals);
+static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand);
+struct mm_struct init_mm = INIT_MM(init_mm);
+
+EXPORT_SYMBOL(init_mm);
+
+union thread_union init_thread_union
+ __attribute__((__section__(".data.init_task"))) =
+{ INIT_THREAD_INFO(init_task) };
+
+struct task_struct init_task = INIT_TASK(init_task);
+
+EXPORT_SYMBOL(init_task);
diff --git a/arch/xtensa/kernel/io.c b/arch/xtensa/kernel/io.c
new file mode 100644
index 00000000000..5b65269b1d2
--- /dev/null
+++ b/arch/xtensa/kernel/io.c
@@ -0,0 +1,75 @@
+/*
+ * arch/xtensa/io.c
+ *
+ * IO primitives
+ *
+ * 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.
+ *
+ * Copied from sparc.
+ *
+ * Chris Zankel <chris@zankel.net>
+ *
+ */
+
+#include <asm/io.h>
+#include <asm/byteorder.h>
+
+void outsb(unsigned long addr, const void *src, unsigned long count) {
+ while (count) {
+ count -= 1;
+ writeb(*(const char *)src, addr);
+ src += 1;
+ addr += 1;
+ }
+}
+
+void outsw(unsigned long addr, const void *src, unsigned long count) {
+ while (count) {
+ count -= 2;
+ writew(*(const short *)src, addr);
+ src += 2;
+ addr += 2;
+ }
+}
+
+void outsl(unsigned long addr, const void *src, unsigned long count) {
+ while (count) {
+ count -= 4;
+ writel(*(const long *)src, addr);
+ src += 4;
+ addr += 4;
+ }
+}
+
+void insb(unsigned long addr, void *dst, unsigned long count) {
+ while (count) {
+ count -= 1;
+ *(unsigned char *)dst = readb(addr);
+ dst += 1;
+ addr += 1;
+ }
+}
+
+void insw(unsigned long addr, void *dst, unsigned long count) {
+ while (count) {
+ count -= 2;
+ *(unsigned short *)dst = readw(addr);
+ dst += 2;
+ addr += 2;
+ }
+}
+
+void insl(unsigned long addr, void *dst, unsigned long count) {
+ while (count) {
+ count -= 4;
+ /*
+ * XXX I am sure we are in for an unaligned trap here.
+ */
+ *(unsigned long *)dst = readl(addr);
+ dst += 4;
+ addr += 4;
+ }
+}
diff --git a/arch/xtensa/kernel/module.c b/arch/xtensa/kernel/module.c
index 2ea1755a085..ddf14dcf2ad 100644
--- a/arch/xtensa/kernel/module.c
+++ b/arch/xtensa/kernel/module.c
@@ -7,7 +7,7 @@
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
- * Copyright (C) 2001 - 2005 Tensilica Inc.
+ * Copyright (C) 2001 - 2006 Tensilica Inc.
*
* Chris Zankel <chris@zankel.net>
*
@@ -22,57 +22,216 @@
#include <linux/kernel.h>
#include <linux/cache.h>
-LIST_HEAD(module_buf_list);
+#undef DEBUG_RELOCATE
void *module_alloc(unsigned long size)
{
- panic("module_alloc not implemented");
+ if (size == 0)
+ return NULL;
+ return vmalloc(size);
}
void module_free(struct module *mod, void *module_region)
{
- panic("module_free not implemented");
+ vfree(module_region);
+ /* FIXME: If module_region == mod->init_region, trim exception
+ table entries. */
}
int module_frob_arch_sections(Elf32_Ehdr *hdr,
Elf32_Shdr *sechdrs,
char *secstrings,
- struct module *me)
+ struct module *mod)
{
- panic("module_frob_arch_sections not implemented");
+ return 0;
+}
+
+static int
+decode_calln_opcode (unsigned char *location)
+{
+#ifdef __XTENSA_EB__
+ return (location[0] & 0xf0) == 0x50;
+#endif
+#ifdef __XTENSA_EL__
+ return (location[0] & 0xf) == 0x5;
+#endif
+}
+
+static int
+decode_l32r_opcode (unsigned char *location)
+{
+#ifdef __XTENSA_EB__
+ return (location[0] & 0xf0) == 0x10;
+#endif
+#ifdef __XTENSA_EL__
+ return (location[0] & 0xf) == 0x1;
+#endif
}
int apply_relocate(Elf32_Shdr *sechdrs,
const char *strtab,
unsigned int symindex,
unsigned int relsec,
- struct module *module)
+ struct module *mod)
{
- panic ("apply_relocate not implemented");
+ printk(KERN_ERR "module %s: REL RELOCATION unsupported\n",
+ mod->name);
+ return -ENOEXEC;
+
}
int apply_relocate_add(Elf32_Shdr *sechdrs,
const char *strtab,
unsigned int symindex,
unsigned int relsec,
- struct module *module)
+ struct module *mod)
{
- panic("apply_relocate_add not implemented");
+ unsigned int i;
+ Elf32_Rela *rela = (void *)sechdrs[relsec].sh_addr;
+ Elf32_Sym *sym;
+ unsigned char *location;
+ uint32_t value;
+
+#ifdef DEBUG_RELOCATE
+ printk("Applying relocate section %u to %u\n", relsec,
+ sechdrs[relsec].sh_info);
+#endif
+ for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rela); i++) {
+ location = (char *)sechdrs[sechdrs[relsec].sh_info].sh_addr
+ + rela[i].r_offset;
+ sym = (Elf32_Sym *)sechdrs[symindex].sh_addr
+ + ELF32_R_SYM(rela[i].r_info);
+ value = sym->st_value + rela[i].r_addend;
+
+ switch (ELF32_R_TYPE(rela[i].r_info)) {
+ case R_XTENSA_NONE:
+ case R_XTENSA_DIFF8:
+ case R_XTENSA_DIFF16:
+ case R_XTENSA_DIFF32:
+ case R_XTENSA_ASM_EXPAND:
+ break;
+
+ case R_XTENSA_32:
+ case R_XTENSA_PLT:
+ *(uint32_t *)location += value;
+ break;
+
+ case R_XTENSA_SLOT0_OP:
+ if (decode_calln_opcode(location)) {
+ value -= ((unsigned long)location & -4) + 4;
+ if ((value & 3) != 0 ||
+ ((value + (1 << 19)) >> 20) != 0) {
+ printk("%s: relocation out of range, "
+ "section %d reloc %d "
+ "sym '%s'\n",
+ mod->name, relsec, i,
+ strtab + sym->st_name);
+ return -ENOEXEC;
+ }
+ value = (signed int)value >> 2;
+#ifdef __XTENSA_EB__
+ location[0] = ((location[0] & ~0x3) |
+ ((value >> 16) & 0x3));
+ location[1] = (value >> 8) & 0xff;
+ location[2] = value & 0xff;
+#endif
+#ifdef __XTENSA_EL__
+ location[0] = ((location[0] & ~0xc0) |
+ ((value << 6) & 0xc0));
+ location[1] = (value >> 2) & 0xff;
+ location[2] = (value >> 10) & 0xff;
+#endif
+ } else if (decode_l32r_opcode(location)) {
+ value -= (((unsigned long)location + 3) & -4);
+ if ((value & 3) != 0 ||
+ (signed int)value >> 18 != -1) {
+ printk("%s: relocation out of range, "
+ "section %d reloc %d "
+ "sym '%s'\n",
+ mod->name, relsec, i,
+ strtab + sym->st_name);
+ return -ENOEXEC;
+ }
+ value = (signed int)value >> 2;
+
+#ifdef __XTENSA_EB__
+ location[1] = (value >> 8) & 0xff;
+ location[2] = value & 0xff;
+#endif
+#ifdef __XTENSA_EL__
+ location[1] = value & 0xff;
+ location[2] = (value >> 8) & 0xff;
+#endif
+ }
+ /* FIXME: Ignore any other opcodes. The Xtensa
+ assembler currently assumes that the linker will
+ always do relaxation and so all PC-relative
+ operands need relocations. (The assembler also
+ writes out the tentative PC-relative values,
+ assuming no link-time relaxation, so it is usually
+ safe to ignore the relocations.) If the
+ assembler's "--no-link-relax" flag can be made to
+ work, and if all kernel modules can be assembled
+ with that flag, then unexpected relocations could
+ be detected here. */
+ break;
+
+ case R_XTENSA_SLOT1_OP:
+ case R_XTENSA_SLOT2_OP:
+ case R_XTENSA_SLOT3_OP:
+ case R_XTENSA_SLOT4_OP:
+ case R_XTENSA_SLOT5_OP:
+ case R_XTENSA_SLOT6_OP:
+ case R_XTENSA_SLOT7_OP:
+ case R_XTENSA_SLOT8_OP:
+ case R_XTENSA_SLOT9_OP:
+ case R_XTENSA_SLOT10_OP:
+ case R_XTENSA_SLOT11_OP:
+ case R_XTENSA_SLOT12_OP:
+ case R_XTENSA_SLOT13_OP:
+ case R_XTENSA_SLOT14_OP:
+ printk("%s: unexpected FLIX relocation: %u\n",
+ mod->name,
+ ELF32_R_TYPE(rela[i].r_info));
+ return -ENOEXEC;
+
+ case R_XTENSA_SLOT0_ALT:
+ case R_XTENSA_SLOT1_ALT:
+ case R_XTENSA_SLOT2_ALT:
+ case R_XTENSA_SLOT3_ALT:
+ case R_XTENSA_SLOT4_ALT:
+ case R_XTENSA_SLOT5_ALT:
+ case R_XTENSA_SLOT6_ALT:
+ case R_XTENSA_SLOT7_ALT:
+ case R_XTENSA_SLOT8_ALT:
+ case R_XTENSA_SLOT9_ALT:
+ case R_XTENSA_SLOT10_ALT:
+ case R_XTENSA_SLOT11_ALT:
+ case R_XTENSA_SLOT12_ALT:
+ case R_XTENSA_SLOT13_ALT:
+ case R_XTENSA_SLOT14_ALT:
+ printk("%s: unexpected ALT relocation: %u\n",
+ mod->name,
+ ELF32_R_TYPE(rela[i].r_info));
+ return -ENOEXEC;
+
+ default:
+ printk("%s: unexpected relocation: %u\n",
+ mod->name,
+ ELF32_R_TYPE(rela[i].r_info));
+ return -ENOEXEC;
+ }
+ }
+ return 0;
}
int module_finalize(const Elf_Ehdr *hdr,
const Elf_Shdr *sechdrs,
- struct module *me)
+ struct module *mod)
{
- panic ("module_finalize not implemented");
+ return 0;
}
void module_arch_cleanup(struct module *mod)
{
- panic("module_arch_cleanup not implemented");
-}
-
-struct bug_entry *module_find_bug(unsigned long bugaddr)
-{
- panic("module_find_bug not implemented");
}
diff --git a/arch/xtensa/kernel/pci.c b/arch/xtensa/kernel/pci.c
index 77deae5290f..b7c073484e0 100644
--- a/arch/xtensa/kernel/pci.c
+++ b/arch/xtensa/kernel/pci.c
@@ -394,72 +394,3 @@ int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
return ret;
}
-
-/*
- * This probably belongs here rather than ioport.c because
- * we do not want this crud linked into SBus kernels.
- * Also, think for a moment about likes of floppy.c that
- * include architecture specific parts. They may want to redefine ins/outs.
- *
- * We do not use horrible macros here because we want to
- * advance pointer by sizeof(size).
- */
-void outsb(unsigned long addr, const void *src, unsigned long count) {
- while (count) {
- count -= 1;
- writeb(*(const char *)src, addr);
- src += 1;
- addr += 1;
- }
-}
-
-void outsw(unsigned long addr, const void *src, unsigned long count) {
- while (count) {
- count -= 2;
- writew(*(const short *)src, addr);
- src += 2;
- addr += 2;
- }
-}
-
-void outsl(unsigned long addr, const void *src, unsigned long count) {
- while (count) {
- count -= 4;
- writel(*(const long *)src, addr);
- src += 4;
- addr += 4;
- }
-}
-
-void insb(unsigned long addr, void *dst, unsigned long count) {
- while (count) {
- count -= 1;
- *(unsigned char *)dst = readb(addr);
- dst += 1;
- addr += 1;
- }
-}
-
-void insw(unsigned long addr, void *dst, unsigned long count) {
- while (count) {
- count -= 2;
- *(unsigned short *)dst = readw(addr);
- dst += 2;
- addr += 2;
- }
-}
-
-void insl(unsigned long addr, void *dst, unsigned long count) {
- while (count) {
- count -= 4;
- /*
- * XXX I am sure we are in for an unaligned trap here.
- */
- *(unsigned long *)dst = readl(addr);
- dst += 4;
- addr += 4;
- }
-}
-
-
-
diff --git a/arch/xtensa/kernel/process.c b/arch/xtensa/kernel/process.c
index dd498f1604e..f53d7bd9dfb 100644
--- a/arch/xtensa/kernel/process.c
+++ b/arch/xtensa/kernel/process.c
@@ -46,20 +46,6 @@
extern void ret_from_fork(void);
-static struct fs_struct init_fs = INIT_FS;
-static struct files_struct init_files = INIT_FILES;
-static struct signal_struct init_signals = INIT_SIGNALS(init_signals);
-static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand);
-struct mm_struct init_mm = INIT_MM(init_mm);
-EXPORT_SYMBOL(init_mm);
-
-union thread_union init_thread_union
- __attribute__((__section__(".data.init_task"))) =
-{ INIT_THREAD_INFO(init_task) };
-
-struct task_struct init_task = INIT_TASK(init_task);
-EXPORT_SYMBOL(init_task);
-
struct task_struct *current_set[NR_CPUS] = {&init_task, };
void (*pm_power_off)(void) = NULL;
diff --git a/arch/xtensa/kernel/semaphore.c b/arch/xtensa/kernel/semaphore.c
index d40f4b1b75a..995c6410ae1 100644
--- a/arch/xtensa/kernel/semaphore.c
+++ b/arch/xtensa/kernel/semaphore.c
@@ -100,7 +100,7 @@ static __inline__ int waking_non_zero_trylock(struct semaphore *sem)
return ret;
}
-spinlock_t semaphore_wake_lock;
+DEFINE_SPINLOCK(semaphore_wake_lock);
/*
* Semaphores are implemented using a two-way counter:
diff --git a/arch/xtensa/kernel/syscall.c b/arch/xtensa/kernel/syscall.c
index fe3834bc1db..f3e16efcd47 100644
--- a/arch/xtensa/kernel/syscall.c
+++ b/arch/xtensa/kernel/syscall.c
@@ -93,3 +93,8 @@ asmlinkage long xtensa_shmat(int shmid, char __user *shmaddr, int shmflg)
return (long)ret;
}
+asmlinkage long xtensa_fadvise64_64(int fd, int advice, unsigned long long offset, unsigned long long len)
+{
+ return sys_fadvise64_64(fd, offset, len, advice);
+}
+
diff --git a/arch/xtensa/kernel/time.c b/arch/xtensa/kernel/time.c
index 22949be4a5d..60d29fe0b1b 100644
--- a/arch/xtensa/kernel/time.c
+++ b/arch/xtensa/kernel/time.c
@@ -32,12 +32,20 @@ EXPORT_SYMBOL(rtc_lock);
#ifdef CONFIG_XTENSA_CALIBRATE_CCOUNT
unsigned long ccount_per_jiffy; /* per 1/HZ */
-unsigned long ccount_nsec; /* nsec per ccount increment */
+unsigned long nsec_per_ccount; /* nsec per ccount increment */
#endif
-unsigned int last_ccount_stamp;
static long last_rtc_update = 0;
+/*
+ * Scheduler clock - returns current tim in nanosec units.
+ */
+
+unsigned long long sched_clock(void)
+{
+ return (unsigned long long)jiffies * (1000000000 / HZ);
+}
+
static irqreturn_t timer_interrupt(int irq, void *dev_id);
static struct irqaction timer_irqaction = {
.handler = timer_interrupt,
@@ -69,7 +77,6 @@ void __init time_init(void)
xtime.tv_nsec = 0;
last_rtc_update = xtime.tv_sec = sec_n;
- last_ccount_stamp = get_ccount();
set_normalized_timespec(&wall_to_monotonic,
-xtime.tv_sec, -xtime.tv_nsec);
@@ -85,7 +92,7 @@ int do_settimeofday(struct timespec *tv)
{
time_t wtm_sec, sec = tv->tv_sec;
long wtm_nsec, nsec = tv->tv_nsec;
- unsigned long ccount;
+ unsigned long delta;
if ((unsigned long)tv->tv_nsec >= NSEC_PER_SEC)
return -EINVAL;
@@ -97,8 +104,10 @@ int do_settimeofday(struct timespec *tv)
* wall time. Discover what correction gettimeofday() would have
* made, and then undo it!
*/
- ccount = get_ccount();
- nsec -= (ccount - last_ccount_stamp) * CCOUNT_NSEC;
+
+ delta = CCOUNT_PER_JIFFY;
+ delta += get_ccount() - get_linux_timer();
+ nsec -= delta * NSEC_PER_CCOUNT;
wtm_sec = wall_to_monotonic.tv_sec + (xtime.tv_sec - sec);
wtm_nsec = wall_to_monotonic.tv_nsec + (xtime.tv_nsec - nsec);
@@ -117,17 +126,21 @@ EXPORT_SYMBOL(do_settimeofday);
void do_gettimeofday(struct timeval *tv)
{
unsigned long flags;
- unsigned long sec, usec, delta, seq;
+ unsigned long volatile sec, usec, delta, seq;
do {
seq = read_seqbegin_irqsave(&xtime_lock, flags);
- delta = get_ccount() - last_ccount_stamp;
sec = xtime.tv_sec;
usec = (xtime.tv_nsec / NSEC_PER_USEC);
+
+ delta = get_linux_timer() - get_ccount();
+
} while (read_seqretry_irqrestore(&xtime_lock, seq, flags));
- usec += (delta * CCOUNT_NSEC) / NSEC_PER_USEC;
+ usec += (((unsigned long) CCOUNT_PER_JIFFY - delta)
+ * (unsigned long) NSEC_PER_CCOUNT) / NSEC_PER_USEC;
+
for (; usec >= 1000000; sec++, usec -= 1000000)
;
@@ -158,9 +171,12 @@ again:
write_seqlock(&xtime_lock);
- last_ccount_stamp = next;
+ do_timer(1); /* Linux handler in kernel/timer.c */
+
+ /* Note that writing CCOMPARE clears the interrupt. */
+
next += CCOUNT_PER_JIFFY;
- do_timer (1); /* Linux handler in kernel/timer.c */
+ set_linux_timer(next);
if (ntp_synced() &&
xtime.tv_sec - last_rtc_update >= 659 &&
@@ -175,19 +191,15 @@ again:
write_sequnlock(&xtime_lock);
}
- /* NOTE: writing CCOMPAREn clears the interrupt. */
+ /* Allow platform to do something useful (Wdog). */
- set_linux_timer (next);
+ platform_heartbeat();
/* Make sure we didn't miss any tick... */
if ((signed long)(get_ccount() - next) > 0)
goto again;
- /* Allow platform to do something useful (Wdog). */
-
- platform_heartbeat();
-
return IRQ_HANDLED;
}
diff --git a/arch/xtensa/kernel/traps.c b/arch/xtensa/kernel/traps.c
index c5e62f9d9f5..8be99c777d9 100644
--- a/arch/xtensa/kernel/traps.c
+++ b/arch/xtensa/kernel/traps.c
@@ -83,7 +83,7 @@ typedef struct {
void* handler;
} dispatch_init_table_t;
-dispatch_init_table_t __init dispatch_init_table[] = {
+static dispatch_init_table_t __initdata dispatch_init_table[] = {
{ EXCCAUSE_ILLEGAL_INSTRUCTION, 0, do_illegal_instruction},
{ EXCCAUSE_SYSTEM_CALL, KRNL, fast_syscall_kernel },
@@ -305,7 +305,7 @@ do_debug(struct pt_regs *regs)
#define set_handler(idx,handler) (exc_table[idx] = (unsigned long) (handler))
-void trap_init(void)
+void __init trap_init(void)
{
int i;
diff --git a/arch/xtensa/mm/Makefile b/arch/xtensa/mm/Makefile
index a5aed5932d7..10aec22a8f9 100644
--- a/arch/xtensa/mm/Makefile
+++ b/arch/xtensa/mm/Makefile
@@ -5,9 +5,5 @@
# removes any old dependencies. DON'T put your own dependencies here
# unless it's something special (ie not a .c file).
#
-# Note 2! The CFLAGS definition is now in the main makefile...
-obj-y := init.o fault.o tlb.o misc.o
-obj-m :=
-obj-n :=
-obj- :=
+obj-y := init.o fault.o tlb.o misc.o cache.o
diff --git a/arch/xtensa/mm/cache.c b/arch/xtensa/mm/cache.c
new file mode 100644
index 00000000000..9a1fa9478ae
--- /dev/null
+++ b/arch/xtensa/mm/cache.c
@@ -0,0 +1,256 @@
+/*
+ * arch/xtensa/mm/cache.c
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2001-2006 Tensilica Inc.
+ *
+ * Chris Zankel <chris@zankel.net>
+ * Joe Taylor
+ * Marc Gauthier
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/types.h>
+#include <linux/ptrace.h>
+#include <linux/bootmem.h>
+#include <linux/swap.h>
+#include <linux/pagemap.h>
+
+#include <asm/pgtable.h>
+#include <asm/bootparam.h>
+#include <asm/mmu_context.h>
+#include <asm/tlb.h>
+#include <asm/tlbflush.h>
+#include <asm/page.h>
+#include <asm/pgalloc.h>
+#include <asm/pgtable.h>
+
+//#define printd(x...) printk(x)
+#define printd(x...) do { } while(0)
+
+/*
+ * Note:
+ * The kernel provides one architecture bit PG_arch_1 in the page flags that
+ * can be used for cache coherency.
+ *
+ * I$-D$ coherency.
+ *
+ * The Xtensa architecture doesn't keep the instruction cache coherent with
+ * the data cache. We use the architecture bit to indicate if the caches
+ * are coherent. The kernel clears this bit whenever a page is added to the
+ * page cache. At that time, the caches might not be in sync. We, therefore,
+ * define this flag as 'clean' if set.
+ *
+ * D-cache aliasing.
+ *
+ * With cache aliasing, we have to always flush the cache when pages are
+ * unmapped (see tlb_start_vma(). So, we use this flag to indicate a dirty
+ * page.
+ *
+ *
+ *
+ */
+
+#if (DCACHE_WAY_SIZE > PAGE_SIZE) && XCHAL_DCACHE_IS_WRITEBACK
+
+/*
+ * Any time the kernel writes to a user page cache page, or it is about to
+ * read from a page cache page this routine is called.
+ *
+ */
+
+void flush_dcache_page(struct page *page)
+{
+ struct address_space *mapping = page_mapping(page);
+
+ /*
+ * If we have a mapping but the page is not mapped to user-space
+ * yet, we simply mark this page dirty and defer flushing the
+ * caches until update_mmu().
+ */
+
+ if (mapping && !mapping_mapped(mapping)) {
+ if (!test_bit(PG_arch_1, &page->flags))
+ set_bit(PG_arch_1, &page->flags);
+ return;
+
+ } else {
+
+ unsigned long phys = page_to_phys(page);
+ unsigned long temp = page->index << PAGE_SHIFT;
+ unsigned long alias = !(DCACHE_ALIAS_EQ(temp, phys));
+ unsigned long virt;
+
+ /*
+ * Flush the page in kernel space and user space.
+ * Note that we can omit that step if aliasing is not
+ * an issue, but we do have to synchronize I$ and D$
+ * if we have a mapping.
+ */
+
+ if (!alias && !mapping)
+ return;
+
+ __flush_invalidate_dcache_page((long)page_address(page));
+
+ virt = TLBTEMP_BASE_1 + (temp & DCACHE_ALIAS_MASK);
+
+ if (alias)
+ __flush_invalidate_dcache_page_alias(virt, phys);
+
+ if (mapping)
+ __invalidate_icache_page_alias(virt, phys);
+ }
+
+ /* There shouldn't be an entry in the cache for this page anymore. */
+}
+
+
+/*
+ * For now, flush the whole cache. FIXME??
+ */
+
+void flush_cache_range(struct vm_area_struct* vma,
+ unsigned long start, unsigned long end)
+{
+ __flush_invalidate_dcache_all();
+ __invalidate_icache_all();
+}
+
+/*
+ * Remove any entry in the cache for this page.
+ *
+ * Note that this function is only called for user pages, so use the
+ * alias versions of the cache flush functions.
+ */
+
+void flush_cache_page(struct vm_area_struct* vma, unsigned long address,
+ unsigned long pfn)
+{
+ /* Note that we have to use the 'alias' address to avoid multi-hit */
+
+ unsigned long phys = page_to_phys(pfn_to_page(pfn));
+ unsigned long virt = TLBTEMP_BASE_1 + (address & DCACHE_ALIAS_MASK);
+
+ __flush_invalidate_dcache_page_alias(virt, phys);
+ __invalidate_icache_page_alias(virt, phys);
+}
+
+#endif
+
+void
+update_mmu_cache(struct vm_area_struct * vma, unsigned long addr, pte_t pte)
+{
+ unsigned long pfn = pte_pfn(pte);
+ struct page *page;
+
+ if (!pfn_valid(pfn))
+ return;
+
+ page = pfn_to_page(pfn);
+
+ /* Invalidate old entry in TLBs */
+
+ invalidate_itlb_mapping(addr);
+ invalidate_dtlb_mapping(addr);
+
+#if (DCACHE_WAY_SIZE > PAGE_SIZE) && XCHAL_DCACHE_IS_WRITEBACK
+
+ if (!PageReserved(page) && test_bit(PG_arch_1, &page->flags)) {
+
+ unsigned long vaddr = TLBTEMP_BASE_1 + (addr & DCACHE_ALIAS_MASK);
+ unsigned long paddr = (unsigned long) page_address(page);
+ unsigned long phys = page_to_phys(page);
+
+ __flush_invalidate_dcache_page(paddr);
+
+ __flush_invalidate_dcache_page_alias(vaddr, phys);
+ __invalidate_icache_page_alias(vaddr, phys);
+
+ clear_bit(PG_arch_1, &page->flags);
+ }
+#else
+ if (!PageReserved(page) && !test_bit(PG_arch_1, &page->flags)
+ && (vma->vm_flags & VM_EXEC) != 0) {
+ unsigned long vaddr = addr & PAGE_MASK;
+ __flush_dcache_page(vaddr);
+ __invalidate_icache_page(vaddr);
+ set_bit(PG_arch_1, &page->flags);
+ }
+#endif
+}
+
+/*
+ * access_process_vm() has called get_user_pages(), which has done a
+ * flush_dcache_page() on the page.
+ */
+
+#if (DCACHE_WAY_SIZE > PAGE_SIZE) && XCHAL_DCACHE_IS_WRITEBACK
+
+void copy_to_user_page(struct vm_area_struct *vma, struct page *page,
+ unsigned long vaddr, void *dst, const void *src,
+ unsigned long len)
+{
+ unsigned long phys = page_to_phys(page);
+ unsigned long alias = !(DCACHE_ALIAS_EQ(vaddr, phys));
+
+ /* Flush and invalidate user page if aliased. */
+
+ if (alias) {
+ unsigned long temp = TLBTEMP_BASE_1 + (vaddr & DCACHE_ALIAS_MASK);
+ __flush_invalidate_dcache_page_alias(temp, phys);
+ }
+
+ /* Copy data */
+
+ memcpy(dst, src, len);
+
+ /*
+ * Flush and invalidate kernel page if aliased and synchronize
+ * data and instruction caches for executable pages.
+ */
+
+ if (alias) {
+ unsigned long temp = TLBTEMP_BASE_1 + (vaddr & DCACHE_ALIAS_MASK);
+
+ __flush_invalidate_dcache_range((unsigned long) dst, len);
+ if ((vma->vm_flags & VM_EXEC) != 0) {
+ __invalidate_icache_page_alias(temp, phys);
+ }
+
+ } else if ((vma->vm_flags & VM_EXEC) != 0) {
+ __flush_dcache_range((unsigned long)dst,len);
+ __invalidate_icache_range((unsigned long) dst, len);
+ }
+}
+
+extern void copy_from_user_page(struct vm_area_struct *vma, struct page *page,
+ unsigned long vaddr, void *dst, const void *src,
+ unsigned long len)
+{
+ unsigned long phys = page_to_phys(page);
+ unsigned long alias = !(DCACHE_ALIAS_EQ(vaddr, phys));
+
+ /*
+ * Flush user page if aliased.
+ * (Note: a simply flush would be sufficient)
+ */
+
+ if (alias) {
+ unsigned long temp = TLBTEMP_BASE_1 + (vaddr & DCACHE_ALIAS_MASK);
+ __flush_invalidate_dcache_page_alias(temp, phys);
+ }
+
+ memcpy(dst, src, len);
+}
+
+#endif
diff --git a/arch/xtensa/mm/fault.c b/arch/xtensa/mm/fault.c
index 16004067add..45d28f217c0 100644
--- a/arch/xtensa/mm/fault.c
+++ b/arch/xtensa/mm/fault.c
@@ -24,6 +24,8 @@
unsigned long asid_cache = ASID_USER_FIRST;
void bad_page_fault(struct pt_regs*, unsigned long, int);
+#undef DEBUG_PAGE_FAULT
+
/*
* This routine handles page faults. It determines the address,
* and the problem, and then passes it off to one of the appropriate
@@ -64,7 +66,7 @@ void do_page_fault(struct pt_regs *regs)
exccause == EXCCAUSE_ITLB_MISS ||
exccause == EXCCAUSE_FETCH_CACHE_ATTRIBUTE) ? 1 : 0;
-#if 0
+#ifdef DEBUG_PAGE_FAULT
printk("[%s:%d:%08x:%d:%08x:%s%s]\n", current->comm, current->pid,
address, exccause, regs->pc, is_write? "w":"", is_exec? "x":"");
#endif
@@ -219,7 +221,7 @@ bad_page_fault(struct pt_regs *regs, unsigned long address, int sig)
/* Are we prepared to handle this kernel fault? */
if ((entry = search_exception_tables(regs->pc)) != NULL) {
-#if 1
+#ifdef DEBUG_PAGE_FAULT
printk(KERN_DEBUG "%s: Exception at pc=%#010lx (%lx)\n",
current->comm, regs->pc, entry->fixup);
#endif
diff --git a/arch/xtensa/mm/init.c b/arch/xtensa/mm/init.c
index 8415c76f11c..b3086f34a8e 100644
--- a/arch/xtensa/mm/init.c
+++ b/arch/xtensa/mm/init.c
@@ -15,40 +15,24 @@
* Kevin Chea
*/
-#include <linux/init.h>
-#include <linux/signal.h>
-#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/errno.h>
-#include <linux/string.h>
-#include <linux/types.h>
-#include <linux/ptrace.h>
#include <linux/bootmem.h>
#include <linux/swap.h>
+#include <linux/mman.h>
+#include <linux/nodemask.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
#include <asm/pgtable.h>
#include <asm/bootparam.h>
#include <asm/mmu_context.h>
#include <asm/tlb.h>
-#include <asm/tlbflush.h>
#include <asm/page.h>
#include <asm/pgalloc.h>
-#include <asm/pgtable.h>
-
-#define DEBUG 0
DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
-//static DEFINE_SPINLOCK(tlb_lock);
-
-/*
- * This flag is used to indicate that the page was mapped and modified in
- * kernel space, so the cache is probably dirty at that address.
- * If cache aliasing is enabled and the page color mismatches, update_mmu_cache
- * synchronizes the caches if this bit is set.
- */
-
-#define PG_cache_clean PG_arch_1
/* References to section boundaries */
@@ -323,228 +307,22 @@ void show_mem(void)
printk("%d free pages\n", free);
}
-/* ------------------------------------------------------------------------- */
-
-#if (DCACHE_WAY_SIZE > PAGE_SIZE)
-
-/*
- * With cache aliasing, the page color of the page in kernel space and user
- * space might mismatch. We temporarily map the page to a different virtual
- * address with the same color and clear the page there.
- */
-
-void clear_user_page(void *kaddr, unsigned long vaddr, struct page* page)
-{
-
- /* There shouldn't be any entries for this page. */
-
- __flush_invalidate_dcache_page_phys(__pa(page_address(page)));
-
- if (!PAGE_COLOR_EQ(vaddr, kaddr)) {
- unsigned long v, p;
-
- /* Temporarily map page to DTLB_WAY_DCACHE_ALIAS0. */
-
- spin_lock(&tlb_lock);
-
- p = (unsigned long)pte_val((mk_pte(page,PAGE_KERNEL)));
- kaddr = (void*)PAGE_COLOR_MAP0(vaddr);
- v = (unsigned long)kaddr | DTLB_WAY_DCACHE_ALIAS0;
- __asm__ __volatile__("wdtlb %0,%1; dsync" : :"a" (p), "a" (v));
-
- clear_page(kaddr);
-
- spin_unlock(&tlb_lock);
- } else {
- clear_page(kaddr);
- }
-
- /* We need to make sure that i$ and d$ are coherent. */
-
- clear_bit(PG_cache_clean, &page->flags);
-}
-
-/*
- * With cache aliasing, we have to make sure that the page color of the page
- * in kernel space matches that of the virtual user address before we read
- * the page. If the page color differ, we create a temporary DTLB entry with
- * the corrent page color and use this 'temporary' address as the source.
- * We then use the same approach as in clear_user_page and copy the data
- * to the kernel space and clear the PG_cache_clean bit to synchronize caches
- * later.
- *
- * Note:
- * Instead of using another 'way' for the temporary DTLB entry, we could
- * probably use the same entry that points to the kernel address (after
- * saving the original value and restoring it when we are done).
- */
+struct kmem_cache *pgtable_cache __read_mostly;
-void copy_user_page(void* to, void* from, unsigned long vaddr,
- struct page* to_page)
+static void pgd_ctor(void *addr, struct kmem_cache *cache, unsigned long flags)
{
- /* There shouldn't be any entries for the new page. */
-
- __flush_invalidate_dcache_page_phys(__pa(page_address(to_page)));
-
- spin_lock(&tlb_lock);
-
- if (!PAGE_COLOR_EQ(vaddr, from)) {
- unsigned long v, p, t;
-
- __asm__ __volatile__ ("pdtlb %1,%2; rdtlb1 %0,%1"
- : "=a"(p), "=a"(t) : "a"(from));
- from = (void*)PAGE_COLOR_MAP0(vaddr);
- v = (unsigned long)from | DTLB_WAY_DCACHE_ALIAS0;
- __asm__ __volatile__ ("wdtlb %0,%1; dsync" ::"a" (p), "a" (v));
- }
-
- if (!PAGE_COLOR_EQ(vaddr, to)) {
- unsigned long v, p;
-
- p = (unsigned long)pte_val((mk_pte(to_page,PAGE_KERNEL)));
- to = (void*)PAGE_COLOR_MAP1(vaddr);
- v = (unsigned long)to | DTLB_WAY_DCACHE_ALIAS1;
- __asm__ __volatile__ ("wdtlb %0,%1; dsync" ::"a" (p), "a" (v));
- }
- copy_page(to, from);
-
- spin_unlock(&tlb_lock);
-
- /* We need to make sure that i$ and d$ are coherent. */
-
- clear_bit(PG_cache_clean, &to_page->flags);
-}
-
-
-
-/*
- * Any time the kernel writes to a user page cache page, or it is about to
- * read from a page cache page this routine is called.
- *
- * Note:
- * The kernel currently only provides one architecture bit in the page
- * flags that we use for I$/D$ coherency. Maybe, in future, we can
- * use a sepearte bit for deferred dcache aliasing:
- * If the page is not mapped yet, we only need to set a flag,
- * if mapped, we need to invalidate the page.
- */
-// FIXME: we probably need this for WB caches not only for Page Coloring..
-
-void flush_dcache_page(struct page *page)
-{
- unsigned long addr = __pa(page_address(page));
- struct address_space *mapping = page_mapping(page);
-
- __flush_invalidate_dcache_page_phys(addr);
-
- if (!test_bit(PG_cache_clean, &page->flags))
- return;
-
- /* If this page hasn't been mapped, yet, handle I$/D$ coherency later.*/
-#if 0
- if (mapping && !mapping_mapped(mapping))
- clear_bit(PG_cache_clean, &page->flags);
- else
-#endif
- __invalidate_icache_page_phys(addr);
-}
-
-void flush_cache_range(struct vm_area_struct* vma, unsigned long s,
- unsigned long e)
-{
- __flush_invalidate_cache_all();
-}
-
-void flush_cache_page(struct vm_area_struct* vma, unsigned long address,
- unsigned long pfn)
-{
- struct page *page = pfn_to_page(pfn);
-
- /* Remove any entry for the old mapping. */
-
- if (current->active_mm == vma->vm_mm) {
- unsigned long addr = __pa(page_address(page));
- __flush_invalidate_dcache_page_phys(addr);
- if ((vma->vm_flags & VM_EXEC) != 0)
- __invalidate_icache_page_phys(addr);
- } else {
- BUG();
- }
-}
-
-#endif /* (DCACHE_WAY_SIZE > PAGE_SIZE) */
-
-
-pte_t* pte_alloc_one_kernel (struct mm_struct* mm, unsigned long addr)
-{
- pte_t* pte = (pte_t*)__get_free_pages(GFP_KERNEL|__GFP_REPEAT, 0);
- if (likely(pte)) {
- pte_t* ptep = (pte_t*)(pte_val(*pte) + PAGE_OFFSET);
- int i;
- for (i = 0; i < 1024; i++, ptep++)
- pte_clear(mm, addr, ptep);
- }
- return pte;
-}
-
-struct page* pte_alloc_one(struct mm_struct *mm, unsigned long addr)
-{
- struct page *page;
-
- page = alloc_pages(GFP_KERNEL | __GFP_REPEAT, 0);
-
- if (likely(page)) {
- pte_t* ptep = kmap_atomic(page, KM_USER0);
- int i;
+ pte_t* ptep = (pte_t*)addr;
+ int i;
- for (i = 0; i < 1024; i++, ptep++)
- pte_clear(mm, addr, ptep);
+ for (i = 0; i < 1024; i++, ptep++)
+ pte_clear(NULL, 0, ptep);
- kunmap_atomic(ptep, KM_USER0);
- }
- return page;
}
-
-/*
- * Handle D$/I$ coherency.
- *
- * Note:
- * We only have one architecture bit for the page flags, so we cannot handle
- * cache aliasing, yet.
- */
-
-void
-update_mmu_cache(struct vm_area_struct * vma, unsigned long addr, pte_t pte)
+void __init pgtable_cache_init(void)
{
- unsigned long pfn = pte_pfn(pte);
- struct page *page;
- unsigned long vaddr = addr & PAGE_MASK;
-
- if (!pfn_valid(pfn))
- return;
-
- page = pfn_to_page(pfn);
-
- invalidate_itlb_mapping(addr);
- invalidate_dtlb_mapping(addr);
-
- /* We have a new mapping. Use it. */
-
- write_dtlb_entry(pte, dtlb_probe(addr));
-
- /* If the processor can execute from this page, synchronize D$/I$. */
-
- if ((vma->vm_flags & VM_EXEC) != 0) {
-
- write_itlb_entry(pte, itlb_probe(addr));
-
- /* Synchronize caches, if not clean. */
-
- if (!test_and_set_bit(PG_cache_clean, &page->flags)) {
- __flush_dcache_page(vaddr);
- __invalidate_icache_page(vaddr);
- }
- }
+ pgtable_cache = kmem_cache_create("pgd",
+ PAGE_SIZE, PAGE_SIZE,
+ SLAB_HWCACHE_ALIGN,
+ pgd_ctor);
}
-
diff --git a/arch/xtensa/mm/misc.S b/arch/xtensa/mm/misc.S
index ae085332c60..e1f880368e3 100644
--- a/arch/xtensa/mm/misc.S
+++ b/arch/xtensa/mm/misc.S
@@ -7,29 +7,33 @@
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
- * Copyright (C) 2001 - 2005 Tensilica Inc.
+ * Copyright (C) 2001 - 2007 Tensilica Inc.
*
* Chris Zankel <chris@zankel.net>
*/
-/* Note: we might want to implement some of the loops as zero-overhead-loops,
- * where applicable and if supported by the processor.
- */
#include <linux/linkage.h>
#include <asm/page.h>
#include <asm/pgtable.h>
#include <asm/asmmacro.h>
#include <asm/cacheasm.h>
+#include <asm/tlbflush.h>
+
-/* clear_page (page) */
+/*
+ * clear_page and clear_user_page are the same for non-cache-aliased configs.
+ *
+ * clear_page (unsigned long page)
+ * a2
+ */
ENTRY(clear_page)
entry a1, 16
- addi a4, a2, PAGE_SIZE
- movi a3, 0
-1: s32i a3, a2, 0
+ movi a3, 0
+ __loopi a2, a7, PAGE_SIZE, 32
+ s32i a3, a2, 0
s32i a3, a2, 4
s32i a3, a2, 8
s32i a3, a2, 12
@@ -37,42 +41,277 @@ ENTRY(clear_page)
s32i a3, a2, 20
s32i a3, a2, 24
s32i a3, a2, 28
- addi a2, a2, 32
- blt a2, a4, 1b
+ __endla a2, a7, 32
retw
/*
+ * copy_page and copy_user_page are the same for non-cache-aliased configs.
+ *
* copy_page (void *to, void *from)
- * a2 a3
+ * a2 a3
*/
ENTRY(copy_page)
entry a1, 16
- addi a4, a2, PAGE_SIZE
-
-1: l32i a5, a3, 0
- l32i a6, a3, 4
- l32i a7, a3, 8
- s32i a5, a2, 0
- s32i a6, a2, 4
- s32i a7, a2, 8
- l32i a5, a3, 12
- l32i a6, a3, 16
- l32i a7, a3, 20
- s32i a5, a2, 12
- s32i a6, a2, 16
- s32i a7, a2, 20
- l32i a5, a3, 24
- l32i a6, a3, 28
- s32i a5, a2, 24
- s32i a6, a2, 28
- addi a2, a2, 32
- addi a3, a3, 32
- blt a2, a4, 1b
+ __loopi a2, a4, PAGE_SIZE, 32
+
+ l32i a8, a3, 0
+ l32i a9, a3, 4
+ s32i a8, a2, 0
+ s32i a9, a2, 4
+
+ l32i a8, a3, 8
+ l32i a9, a3, 12
+ s32i a8, a2, 8
+ s32i a9, a2, 12
+
+ l32i a8, a3, 16
+ l32i a9, a3, 20
+ s32i a8, a2, 16
+ s32i a9, a2, 20
+
+ l32i a8, a3, 24
+ l32i a9, a3, 28
+ s32i a8, a2, 24
+ s32i a9, a2, 28
+
+ addi a2, a2, 32
+ addi a3, a3, 32
+
+ __endl a2, a4
+
+ retw
+
+/*
+ * If we have to deal with cache aliasing, we use temporary memory mappings
+ * to ensure that the source and destination pages have the same color as
+ * the virtual address. We use way 0 and 1 for temporary mappings in such cases.
+ *
+ * The temporary DTLB entries shouldn't be flushed by interrupts, but are
+ * flushed by preemptive task switches. Special code in the
+ * fast_second_level_miss handler re-established the temporary mapping.
+ * It requires that the PPNs for the destination and source addresses are
+ * in a6, and a7, respectively.
+ */
+
+/* TLB miss exceptions are treated special in the following region */
+
+ENTRY(__tlbtemp_mapping_start)
+
+#if (DCACHE_WAY_SIZE > PAGE_SIZE)
+
+/*
+ * clear_user_page (void *addr, unsigned long vaddr, struct page *page)
+ * a2 a3 a4
+ */
+
+ENTRY(clear_user_page)
+ entry a1, 32
+
+ /* Mark page dirty and determine alias. */
+
+ movi a7, (1 << PG_ARCH_1)
+ l32i a5, a4, PAGE_FLAGS
+ xor a6, a2, a3
+ extui a3, a3, PAGE_SHIFT, DCACHE_ALIAS_ORDER
+ extui a6, a6, PAGE_SHIFT, DCACHE_ALIAS_ORDER
+ or a5, a5, a7
+ slli a3, a3, PAGE_SHIFT
+ s32i a5, a4, PAGE_FLAGS
+
+ /* Skip setting up a temporary DTLB if not aliased. */
+
+ beqz a6, 1f
+
+ /* Invalidate kernel page. */
+
+ mov a10, a2
+ call8 __invalidate_dcache_page
+
+ /* Setup a temporary DTLB with the color of the VPN */
+
+ movi a4, -PAGE_OFFSET + (PAGE_KERNEL | _PAGE_HW_WRITE)
+ movi a5, TLBTEMP_BASE_1 # virt
+ add a6, a2, a4 # ppn
+ add a2, a5, a3 # add 'color'
+
+ wdtlb a6, a2
+ dsync
+
+1: movi a3, 0
+ __loopi a2, a7, PAGE_SIZE, 32
+ s32i a3, a2, 0
+ s32i a3, a2, 4
+ s32i a3, a2, 8
+ s32i a3, a2, 12
+ s32i a3, a2, 16
+ s32i a3, a2, 20
+ s32i a3, a2, 24
+ s32i a3, a2, 28
+ __endla a2, a7, 32
+
+ bnez a6, 1f
+ retw
+
+ /* We need to invalidate the temporary idtlb entry, if any. */
+
+1: addi a2, a2, -PAGE_SIZE
+ idtlb a2
+ dsync
+
+ retw
+
+/*
+ * copy_page_user (void *to, void *from, unsigned long vaddr, struct page *page)
+ * a2 a3 a4 a5
+ */
+
+ENTRY(copy_user_page)
+
+ entry a1, 32
+
+ /* Mark page dirty and determine alias for destination. */
+
+ movi a8, (1 << PG_ARCH_1)
+ l32i a9, a5, PAGE_FLAGS
+ xor a6, a2, a4
+ xor a7, a3, a4
+ extui a4, a4, PAGE_SHIFT, DCACHE_ALIAS_ORDER
+ extui a6, a6, PAGE_SHIFT, DCACHE_ALIAS_ORDER
+ extui a7, a7, PAGE_SHIFT, DCACHE_ALIAS_ORDER
+ or a9, a9, a8
+ slli a4, a4, PAGE_SHIFT
+ s32i a9, a5, PAGE_FLAGS
+ movi a5, -PAGE_OFFSET + (PAGE_KERNEL | _PAGE_HW_WRITE)
+
+ beqz a6, 1f
+
+ /* Invalidate dcache */
+
+ mov a10, a2
+ call8 __invalidate_dcache_page
+
+ /* Setup a temporary DTLB with a matching color. */
+
+ movi a8, TLBTEMP_BASE_1 # base
+ add a6, a2, a5 # ppn
+ add a2, a8, a4 # add 'color'
+
+ wdtlb a6, a2
+ dsync
+
+ /* Skip setting up a temporary DTLB for destination if not aliased. */
+
+1: beqz a7, 1f
+
+ /* Setup a temporary DTLB with a matching color. */
+
+ movi a8, TLBTEMP_BASE_2 # base
+ add a7, a3, a5 # ppn
+ add a3, a8, a4
+ addi a8, a3, 1 # way1
+
+ wdtlb a7, a8
+ dsync
+
+1: __loopi a2, a4, PAGE_SIZE, 32
+
+ l32i a8, a3, 0
+ l32i a9, a3, 4
+ s32i a8, a2, 0
+ s32i a9, a2, 4
+
+ l32i a8, a3, 8
+ l32i a9, a3, 12
+ s32i a8, a2, 8
+ s32i a9, a2, 12
+
+ l32i a8, a3, 16
+ l32i a9, a3, 20
+ s32i a8, a2, 16
+ s32i a9, a2, 20
+
+ l32i a8, a3, 24
+ l32i a9, a3, 28
+ s32i a8, a2, 24
+ s32i a9, a2, 28
+
+ addi a2, a2, 32
+ addi a3, a3, 32
+
+ __endl a2, a4
+
+ /* We need to invalidate any temporary mapping! */
+
+ bnez a6, 1f
+ bnez a7, 2f
+ retw
+
+1: addi a2, a2, -PAGE_SIZE
+ idtlb a2
+ dsync
+ bnez a7, 2f
+ retw
+
+2: addi a3, a3, -PAGE_SIZE+1
+ idtlb a3
+ dsync
+
+ retw
+
+#endif
+
+#if (DCACHE_WAY_SIZE > PAGE_SIZE)
+
+/*
+ * void __flush_invalidate_dcache_page_alias (addr, phys)
+ * a2 a3
+ */
+
+ENTRY(__flush_invalidate_dcache_page_alias)
+ entry sp, 16
+
+ movi a7, 0 # required for exception handler
+ addi a6, a3, (PAGE_KERNEL | _PAGE_HW_WRITE)
+ mov a4, a2
+ wdtlb a6, a2
+ dsync
+
+ ___flush_invalidate_dcache_page a2 a3
+
+ idtlb a4
+ dsync
+
+ retw
+
+#endif
+
+ENTRY(__tlbtemp_mapping_itlb)
+
+#if (ICACHE_WAY_SIZE > PAGE_SIZE)
+
+ENTRY(__invalidate_icache_page_alias)
+ entry sp, 16
+
+ addi a6, a3, (PAGE_KERNEL | _PAGE_HW_WRITE)
+ mov a4, a2
+ witlb a6, a2
+ isync
+
+ ___invalidate_icache_page a2 a3
+
+ iitlb a4
+ isync
retw
+#endif
+
+/* End of special treatment in tlb miss exception */
+
+ENTRY(__tlbtemp_mapping_end)
+
/*
* void __invalidate_icache_page(ulong start)
*/
@@ -121,8 +360,6 @@ ENTRY(__flush_dcache_page)
dsync
retw
-
-
/*
* void __invalidate_icache_range(ulong start, ulong size)
*/
@@ -168,7 +405,6 @@ ENTRY(__invalidate_dcache_range)
___invalidate_dcache_range a2 a3 a4
-
retw
/*
diff --git a/arch/xtensa/platform-iss/console.c b/arch/xtensa/platform-iss/console.c
index 2f4f20ffe66..854677d0c3f 100644
--- a/arch/xtensa/platform-iss/console.c
+++ b/arch/xtensa/platform-iss/console.c
@@ -20,7 +20,6 @@
#include <linux/param.h>
#include <linux/serial.h>
#include <linux/serialP.h>
-#include <linux/console.h>
#include <asm/uaccess.h>
#include <asm/irq.h>
diff --git a/block/ll_rw_blk.c b/block/ll_rw_blk.c
index a15845c164f..ed39313c408 100644
--- a/block/ll_rw_blk.c
+++ b/block/ll_rw_blk.c
@@ -1075,12 +1075,6 @@ void blk_queue_end_tag(struct request_queue *q, struct request *rq)
*/
return;
- if (unlikely(!__test_and_clear_bit(tag, bqt->tag_map))) {
- printk(KERN_ERR "%s: attempt to clear non-busy tag (%d)\n",
- __FUNCTION__, tag);
- return;
- }
-
list_del_init(&rq->queuelist);
rq->cmd_flags &= ~REQ_QUEUED;
rq->tag = -1;
@@ -1090,6 +1084,19 @@ void blk_queue_end_tag(struct request_queue *q, struct request *rq)
__FUNCTION__, tag);
bqt->tag_index[tag] = NULL;
+
+ /*
+ * We use test_and_clear_bit's memory ordering properties here.
+ * The tag_map bit acts as a lock for tag_index[bit], so we need
+ * a barrer before clearing the bit (precisely: release semantics).
+ * Could use clear_bit_unlock when it is merged.
+ */
+ if (unlikely(!test_and_clear_bit(tag, bqt->tag_map))) {
+ printk(KERN_ERR "%s: attempt to clear non-busy tag (%d)\n",
+ __FUNCTION__, tag);
+ return;
+ }
+
bqt->busy--;
}
@@ -1136,6 +1143,10 @@ int blk_queue_start_tag(struct request_queue *q, struct request *rq)
return 1;
} while (test_and_set_bit(tag, bqt->tag_map));
+ /*
+ * We rely on test_and_set_bit providing lock memory ordering semantics
+ * (could use test_and_set_bit_lock when it is merged).
+ */
rq->cmd_flags |= REQ_QUEUED;
rq->tag = tag;
diff --git a/drivers/acpi/event.c b/drivers/acpi/event.c
index a2b9304596c..5c95863f8fa 100644
--- a/drivers/acpi/event.c
+++ b/drivers/acpi/event.c
@@ -240,7 +240,7 @@ int acpi_bus_generate_netlink_event(const char *device_class,
return 0;
}
-EXPORT_SYMBOL(acpi_generate_netlink_event);
+EXPORT_SYMBOL(acpi_bus_generate_netlink_event);
static int acpi_event_genetlink_init(void)
{
diff --git a/drivers/acpi/processor_core.c b/drivers/acpi/processor_core.c
index e944aaee4e0..2afb3d2086b 100644
--- a/drivers/acpi/processor_core.c
+++ b/drivers/acpi/processor_core.c
@@ -724,6 +724,25 @@ static void acpi_processor_notify(acpi_handle handle, u32 event, void *data)
return;
}
+static int acpi_cpu_soft_notify(struct notifier_block *nfb,
+ unsigned long action, void *hcpu)
+{
+ unsigned int cpu = (unsigned long)hcpu;
+ struct acpi_processor *pr = processors[cpu];
+
+ if (action == CPU_ONLINE && pr) {
+ acpi_processor_ppc_has_changed(pr);
+ acpi_processor_cst_has_changed(pr);
+ acpi_processor_tstate_has_changed(pr);
+ }
+ return NOTIFY_OK;
+}
+
+static struct notifier_block acpi_cpu_notifier =
+{
+ .notifier_call = acpi_cpu_soft_notify,
+};
+
static int acpi_processor_add(struct acpi_device *device)
{
struct acpi_processor *pr = NULL;
@@ -987,6 +1006,7 @@ void acpi_processor_install_hotplug_notify(void)
ACPI_UINT32_MAX,
processor_walk_namespace_cb, &action, NULL);
#endif
+ register_hotcpu_notifier(&acpi_cpu_notifier);
}
static
@@ -999,6 +1019,7 @@ void acpi_processor_uninstall_hotplug_notify(void)
ACPI_UINT32_MAX,
processor_walk_namespace_cb, &action, NULL);
#endif
+ unregister_hotcpu_notifier(&acpi_cpu_notifier);
}
/*
diff --git a/drivers/acpi/sleep/proc.c b/drivers/acpi/sleep/proc.c
index 66b62b0d360..3839efd5eae 100644
--- a/drivers/acpi/sleep/proc.c
+++ b/drivers/acpi/sleep/proc.c
@@ -23,7 +23,7 @@
*/
ACPI_MODULE_NAME("sleep")
-#ifdef CONFIG_ACPI_PROCFS_SLEEP
+#ifdef CONFIG_ACPI_PROCFS
static int acpi_system_sleep_seq_show(struct seq_file *seq, void *offset)
{
int i;
@@ -76,7 +76,7 @@ acpi_system_write_sleep(struct file *file,
Done:
return error ? error : count;
}
-#endif /* CONFIG_ACPI_PROCFS_SLEEP */
+#endif /* CONFIG_ACPI_PROCFS */
#if defined(CONFIG_RTC_DRV_CMOS) || defined(CONFIG_RTC_DRV_CMOS_MODULE) || !defined(CONFIG_X86)
/* use /sys/class/rtc/rtcX/wakealarm instead; it's not ACPI-specific */
@@ -471,7 +471,7 @@ static const struct file_operations acpi_system_wakeup_device_fops = {
.release = single_release,
};
-#ifdef CONFIG_ACPI_PROCFS_SLEEP
+#ifdef CONFIG_ACPI_PROCFS
static const struct file_operations acpi_system_sleep_fops = {
.open = acpi_system_sleep_open_fs,
.read = seq_read,
@@ -479,7 +479,7 @@ static const struct file_operations acpi_system_sleep_fops = {
.llseek = seq_lseek,
.release = single_release,
};
-#endif /* CONFIG_ACPI_PROCFS_SLEEP */
+#endif /* CONFIG_ACPI_PROCFS */
#ifdef HAVE_ACPI_LEGACY_ALARM
static const struct file_operations acpi_system_alarm_fops = {
@@ -506,7 +506,7 @@ static int __init acpi_sleep_proc_init(void)
if (acpi_disabled)
return 0;
-#ifdef CONFIG_ACPI_PROCFS_SLEEP
+#ifdef CONFIG_ACPI_PROCFS
/* 'sleep' [R/W] */
entry =
create_proc_entry("sleep", S_IFREG | S_IRUGO | S_IWUSR,
diff --git a/drivers/base/core.c b/drivers/base/core.c
index e6738bcbe5a..6de33d7a29b 100644
--- a/drivers/base/core.c
+++ b/drivers/base/core.c
@@ -679,14 +679,26 @@ static int device_add_class_symlinks(struct device *dev)
goto out_subsys;
}
if (dev->parent) {
- error = sysfs_create_link(&dev->kobj, &dev->parent->kobj,
- "device");
- if (error)
- goto out_busid;
#ifdef CONFIG_SYSFS_DEPRECATED
{
- char * class_name = make_class_name(dev->class->name,
- &dev->kobj);
+ struct device *parent = dev->parent;
+ char *class_name;
+
+ /*
+ * In old sysfs stacked class devices had 'device'
+ * link pointing to real device instead of parent
+ */
+ while (parent->class && !parent->bus && parent->parent)
+ parent = parent->parent;
+
+ error = sysfs_create_link(&dev->kobj,
+ &parent->kobj,
+ "device");
+ if (error)
+ goto out_busid;
+
+ class_name = make_class_name(dev->class->name,
+ &dev->kobj);
if (class_name)
error = sysfs_create_link(&dev->parent->kobj,
&dev->kobj, class_name);
@@ -694,6 +706,11 @@ static int device_add_class_symlinks(struct device *dev)
if (error)
goto out_device;
}
+#else
+ error = sysfs_create_link(&dev->kobj, &dev->parent->kobj,
+ "device");
+ if (error)
+ goto out_busid;
#endif
}
return 0;
diff --git a/drivers/block/DAC960.c b/drivers/block/DAC960.c
index 504a95d888b..84d6aa500e2 100644
--- a/drivers/block/DAC960.c
+++ b/drivers/block/DAC960.c
@@ -31,6 +31,7 @@
#include <linux/genhd.h>
#include <linux/hdreg.h>
#include <linux/blkpg.h>
+#include <linux/dma-mapping.h>
#include <linux/interrupt.h>
#include <linux/ioport.h>
#include <linux/mm.h>
diff --git a/drivers/char/agp/agp.h b/drivers/char/agp/agp.h
index 35ab1a9f8e8..8955e7ff759 100644
--- a/drivers/char/agp/agp.h
+++ b/drivers/char/agp/agp.h
@@ -176,7 +176,7 @@ struct agp_bridge_data {
#define I830_GMCH_MEM_MASK 0x1
#define I830_GMCH_MEM_64M 0x1
#define I830_GMCH_MEM_128M 0
-#define I830_GMCH_GMS_MASK 0xF0
+#define I830_GMCH_GMS_MASK 0x70
#define I830_GMCH_GMS_DISABLED 0x00
#define I830_GMCH_GMS_LOCAL 0x10
#define I830_GMCH_GMS_STOLEN_512 0x20
@@ -190,6 +190,7 @@ struct agp_bridge_data {
#define INTEL_I830_ERRSTS 0x92
/* Intel 855GM/852GM registers */
+#define I855_GMCH_GMS_MASK 0xF0
#define I855_GMCH_GMS_STOLEN_0M 0x0
#define I855_GMCH_GMS_STOLEN_1M (0x1 << 4)
#define I855_GMCH_GMS_STOLEN_4M (0x2 << 4)
diff --git a/drivers/char/agp/intel-agp.c b/drivers/char/agp/intel-agp.c
index 7c69bf259ca..a5d0e95a227 100644
--- a/drivers/char/agp/intel-agp.c
+++ b/drivers/char/agp/intel-agp.c
@@ -511,7 +511,7 @@ static void intel_i830_init_gtt_entries(void)
*/
if (IS_G33)
size = 0;
- switch (gmch_ctrl & I830_GMCH_GMS_MASK) {
+ switch (gmch_ctrl & I855_GMCH_GMS_MASK) {
case I855_GMCH_GMS_STOLEN_1M:
gtt_entries = MB(1) - KB(size);
break;
diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c
index f2e5cb1bedf..1dd3a065f57 100644
--- a/drivers/char/ipmi/ipmi_si_intf.c
+++ b/drivers/char/ipmi/ipmi_si_intf.c
@@ -2215,7 +2215,8 @@ static int ipmi_pci_resume(struct pci_dev *pdev)
static struct pci_device_id ipmi_pci_devices[] = {
{ PCI_DEVICE(PCI_HP_VENDOR_ID, PCI_MMC_DEVICE_ID) },
- { PCI_DEVICE_CLASS(PCI_ERMC_CLASSCODE, PCI_ERMC_CLASSCODE_MASK) }
+ { PCI_DEVICE_CLASS(PCI_ERMC_CLASSCODE, PCI_ERMC_CLASSCODE_MASK) },
+ { 0, }
};
MODULE_DEVICE_TABLE(pci, ipmi_pci_devices);
diff --git a/drivers/char/mspec.c b/drivers/char/mspec.c
index c08a4152ee8..049a46cc9f8 100644
--- a/drivers/char/mspec.c
+++ b/drivers/char/mspec.c
@@ -67,7 +67,7 @@
/*
* Page types allocated by the device.
*/
-enum {
+enum mspec_page_type {
MSPEC_FETCHOP = 1,
MSPEC_CACHED,
MSPEC_UNCACHED
@@ -83,15 +83,25 @@ static int is_sn2;
* One of these structures is allocated when an mspec region is mmaped. The
* structure is pointed to by the vma->vm_private_data field in the vma struct.
* This structure is used to record the addresses of the mspec pages.
+ * This structure is shared by all vma's that are split off from the
+ * original vma when split_vma()'s are done.
+ *
+ * The refcnt is incremented atomically because mm->mmap_sem does not
+ * protect in fork case where multiple tasks share the vma_data.
*/
struct vma_data {
atomic_t refcnt; /* Number of vmas sharing the data. */
- spinlock_t lock; /* Serialize access to the vma. */
+ spinlock_t lock; /* Serialize access to this structure. */
int count; /* Number of pages allocated. */
- int type; /* Type of pages allocated. */
+ enum mspec_page_type type; /* Type of pages allocated. */
+ int flags; /* See VMD_xxx below. */
+ unsigned long vm_start; /* Original (unsplit) base. */
+ unsigned long vm_end; /* Original (unsplit) end. */
unsigned long maddr[0]; /* Array of MSPEC addresses. */
};
+#define VMD_VMALLOCED 0x1 /* vmalloc'd rather than kmalloc'd */
+
/* used on shub2 to clear FOP cache in the HUB */
static unsigned long scratch_page[MAX_NUMNODES];
#define SH2_AMO_CACHE_ENTRIES 4
@@ -129,8 +139,8 @@ mspec_zero_block(unsigned long addr, int len)
* mspec_open
*
* Called when a device mapping is created by a means other than mmap
- * (via fork, etc.). Increments the reference count on the underlying
- * mspec data so it is not freed prematurely.
+ * (via fork, munmap, etc.). Increments the reference count on the
+ * underlying mspec data so it is not freed prematurely.
*/
static void
mspec_open(struct vm_area_struct *vma)
@@ -151,34 +161,44 @@ static void
mspec_close(struct vm_area_struct *vma)
{
struct vma_data *vdata;
- int i, pages, result, vdata_size;
+ int index, last_index, result;
+ unsigned long my_page;
vdata = vma->vm_private_data;
- if (!atomic_dec_and_test(&vdata->refcnt))
- return;
- pages = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT;
- vdata_size = sizeof(struct vma_data) + pages * sizeof(long);
- for (i = 0; i < pages; i++) {
- if (vdata->maddr[i] == 0)
+ BUG_ON(vma->vm_start < vdata->vm_start || vma->vm_end > vdata->vm_end);
+
+ spin_lock(&vdata->lock);
+ index = (vma->vm_start - vdata->vm_start) >> PAGE_SHIFT;
+ last_index = (vma->vm_end - vdata->vm_start) >> PAGE_SHIFT;
+ for (; index < last_index; index++) {
+ if (vdata->maddr[index] == 0)
continue;
/*
* Clear the page before sticking it back
* into the pool.
*/
- result = mspec_zero_block(vdata->maddr[i], PAGE_SIZE);
+ my_page = vdata->maddr[index];
+ vdata->maddr[index] = 0;
+ spin_unlock(&vdata->lock);
+ result = mspec_zero_block(my_page, PAGE_SIZE);
if (!result)
- uncached_free_page(vdata->maddr[i]);
+ uncached_free_page(my_page);
else
printk(KERN_WARNING "mspec_close(): "
"failed to zero page %i\n",
result);
+ spin_lock(&vdata->lock);
}
+ spin_unlock(&vdata->lock);
- if (vdata_size <= PAGE_SIZE)
- kfree(vdata);
- else
+ if (!atomic_dec_and_test(&vdata->refcnt))
+ return;
+
+ if (vdata->flags & VMD_VMALLOCED)
vfree(vdata);
+ else
+ kfree(vdata);
}
@@ -195,7 +215,8 @@ mspec_nopfn(struct vm_area_struct *vma, unsigned long address)
int index;
struct vma_data *vdata = vma->vm_private_data;
- index = (address - vma->vm_start) >> PAGE_SHIFT;
+ BUG_ON(address < vdata->vm_start || address >= vdata->vm_end);
+ index = (address - vdata->vm_start) >> PAGE_SHIFT;
maddr = (volatile unsigned long) vdata->maddr[index];
if (maddr == 0) {
maddr = uncached_alloc_page(numa_node_id());
@@ -237,10 +258,11 @@ static struct vm_operations_struct mspec_vm_ops = {
* underlying pages.
*/
static int
-mspec_mmap(struct file *file, struct vm_area_struct *vma, int type)
+mspec_mmap(struct file *file, struct vm_area_struct *vma,
+ enum mspec_page_type type)
{
struct vma_data *vdata;
- int pages, vdata_size;
+ int pages, vdata_size, flags = 0;
if (vma->vm_pgoff != 0)
return -EINVAL;
@@ -255,12 +277,17 @@ mspec_mmap(struct file *file, struct vm_area_struct *vma, int type)
vdata_size = sizeof(struct vma_data) + pages * sizeof(long);
if (vdata_size <= PAGE_SIZE)
vdata = kmalloc(vdata_size, GFP_KERNEL);
- else
+ else {
vdata = vmalloc(vdata_size);
+ flags = VMD_VMALLOCED;
+ }
if (!vdata)
return -ENOMEM;
memset(vdata, 0, vdata_size);
+ vdata->vm_start = vma->vm_start;
+ vdata->vm_end = vma->vm_end;
+ vdata->flags = flags;
vdata->type = type;
spin_lock_init(&vdata->lock);
vdata->refcnt = ATOMIC_INIT(1);
diff --git a/drivers/char/tty_ioctl.c b/drivers/char/tty_ioctl.c
index 4a8969cef31..3ee73cf64bd 100644
--- a/drivers/char/tty_ioctl.c
+++ b/drivers/char/tty_ioctl.c
@@ -795,6 +795,19 @@ int n_tty_ioctl(struct tty_struct * tty, struct file * file,
if (L_ICANON(tty))
retval = inq_canon(tty);
return put_user(retval, (unsigned int __user *) arg);
+#ifndef TCGETS2
+ case TIOCGLCKTRMIOS:
+ if (kernel_termios_to_user_termios((struct termios __user *)arg, real_tty->termios_locked))
+ return -EFAULT;
+ return 0;
+
+ case TIOCSLCKTRMIOS:
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+ if (user_termios_to_kernel_termios(real_tty->termios_locked, (struct termios __user *) arg))
+ return -EFAULT;
+ return 0;
+#else
case TIOCGLCKTRMIOS:
if (kernel_termios_to_user_termios_1((struct termios __user *)arg, real_tty->termios_locked))
return -EFAULT;
@@ -806,6 +819,7 @@ int n_tty_ioctl(struct tty_struct * tty, struct file * file,
if (user_termios_to_kernel_termios_1(real_tty->termios_locked, (struct termios __user *) arg))
return -EFAULT;
return 0;
+#endif
case TIOCPKT:
{
diff --git a/drivers/ide/ide-disk.c b/drivers/ide/ide-disk.c
index eba1adbc1b6..4754769eda9 100644
--- a/drivers/ide/ide-disk.c
+++ b/drivers/ide/ide-disk.c
@@ -487,6 +487,7 @@ static inline int idedisk_supports_lba48(const struct hd_driveid *id)
*/
static const struct drive_list_entry hpa_list[] = {
{ "ST340823A", NULL },
+ { "ST320413A", NULL },
{ NULL, NULL }
};
diff --git a/drivers/ide/ppc/pmac.c b/drivers/ide/ppc/pmac.c
index 4b13cd9a027..f19eb6daeef 100644
--- a/drivers/ide/ppc/pmac.c
+++ b/drivers/ide/ppc/pmac.c
@@ -1802,9 +1802,7 @@ pmac_ide_dma_check(ide_drive_t *drive)
{
struct hd_driveid *id = drive->id;
ide_hwif_t *hwif = HWIF(drive);
- pmac_ide_hwif_t* pmif = (pmac_ide_hwif_t *)hwif->hwif_data;
int enable = 1;
- int map;
drive->using_dma = 0;
if (drive->media == ide_floppy)
diff --git a/drivers/kvm/kvm.h b/drivers/kvm/kvm.h
index 3ac9cbce336..336be86c6f5 100644
--- a/drivers/kvm/kvm.h
+++ b/drivers/kvm/kvm.h
@@ -619,7 +619,7 @@ unsigned long segment_base(u16 selector);
void kvm_mmu_pte_write(struct kvm_vcpu *vcpu, gpa_t gpa,
const u8 *old, const u8 *new, int bytes);
int kvm_mmu_unprotect_page_virt(struct kvm_vcpu *vcpu, gva_t gva);
-void kvm_mmu_free_some_pages(struct kvm_vcpu *vcpu);
+void __kvm_mmu_free_some_pages(struct kvm_vcpu *vcpu);
int kvm_mmu_load(struct kvm_vcpu *vcpu);
void kvm_mmu_unload(struct kvm_vcpu *vcpu);
@@ -628,11 +628,15 @@ int kvm_hypercall(struct kvm_vcpu *vcpu, struct kvm_run *run);
static inline int kvm_mmu_page_fault(struct kvm_vcpu *vcpu, gva_t gva,
u32 error_code)
{
- if (unlikely(vcpu->kvm->n_free_mmu_pages < KVM_MIN_FREE_MMU_PAGES))
- kvm_mmu_free_some_pages(vcpu);
return vcpu->mmu.page_fault(vcpu, gva, error_code);
}
+static inline void kvm_mmu_free_some_pages(struct kvm_vcpu *vcpu)
+{
+ if (unlikely(vcpu->kvm->n_free_mmu_pages < KVM_MIN_FREE_MMU_PAGES))
+ __kvm_mmu_free_some_pages(vcpu);
+}
+
static inline int kvm_mmu_reload(struct kvm_vcpu *vcpu)
{
if (likely(vcpu->mmu.root_hpa != INVALID_PAGE))
diff --git a/drivers/kvm/mmu.c b/drivers/kvm/mmu.c
index 1a87ba9d515..23965aa5ee7 100644
--- a/drivers/kvm/mmu.c
+++ b/drivers/kvm/mmu.c
@@ -273,12 +273,14 @@ static int mmu_topup_memory_caches(struct kvm_vcpu *vcpu)
int r;
r = __mmu_topup_memory_caches(vcpu, GFP_NOWAIT);
+ kvm_mmu_free_some_pages(vcpu);
if (r < 0) {
spin_unlock(&vcpu->kvm->lock);
kvm_arch_ops->vcpu_put(vcpu);
r = __mmu_topup_memory_caches(vcpu, GFP_KERNEL);
kvm_arch_ops->vcpu_load(vcpu);
spin_lock(&vcpu->kvm->lock);
+ kvm_mmu_free_some_pages(vcpu);
}
return r;
}
@@ -1208,7 +1210,7 @@ int kvm_mmu_unprotect_page_virt(struct kvm_vcpu *vcpu, gva_t gva)
return kvm_mmu_unprotect_page(vcpu, gpa >> PAGE_SHIFT);
}
-void kvm_mmu_free_some_pages(struct kvm_vcpu *vcpu)
+void __kvm_mmu_free_some_pages(struct kvm_vcpu *vcpu)
{
while (vcpu->kvm->n_free_mmu_pages < KVM_REFILL_PAGES) {
struct kvm_mmu_page *page;
@@ -1218,7 +1220,6 @@ void kvm_mmu_free_some_pages(struct kvm_vcpu *vcpu)
kvm_mmu_zap_page(vcpu->kvm, page);
}
}
-EXPORT_SYMBOL_GPL(kvm_mmu_free_some_pages);
static void free_mmu_pages(struct kvm_vcpu *vcpu)
{
diff --git a/drivers/md/dm-bio-list.h b/drivers/md/dm-bio-list.h
index 16ee3b018b3..3f7b827649e 100644
--- a/drivers/md/dm-bio-list.h
+++ b/drivers/md/dm-bio-list.h
@@ -9,6 +9,8 @@
#include <linux/bio.h>
+#ifdef CONFIG_BLOCK
+
struct bio_list {
struct bio *head;
struct bio *tail;
@@ -106,4 +108,5 @@ static inline struct bio *bio_list_get(struct bio_list *bl)
return bio;
}
+#endif /* CONFIG_BLOCK */
#endif
diff --git a/drivers/media/video/cx88/cx88-mpeg.c b/drivers/media/video/cx88/cx88-mpeg.c
index 317a2a3f9cc..da7a6b591a6 100644
--- a/drivers/media/video/cx88/cx88-mpeg.c
+++ b/drivers/media/video/cx88/cx88-mpeg.c
@@ -580,7 +580,7 @@ struct cx8802_dev * cx8802_get_device(struct inode *inode)
list_for_each(list,&cx8802_devlist) {
h = list_entry(list, struct cx8802_dev, devlist);
- if (h->mpeg_dev->minor == minor)
+ if (h->mpeg_dev && h->mpeg_dev->minor == minor)
return h;
}
diff --git a/drivers/media/video/ivtv/ivtv-fileops.c b/drivers/media/video/ivtv/ivtv-fileops.c
index 5dd519caf81..0285c4a830e 100644
--- a/drivers/media/video/ivtv/ivtv-fileops.c
+++ b/drivers/media/video/ivtv/ivtv-fileops.c
@@ -190,7 +190,9 @@ static void ivtv_update_pgm_info(struct ivtv *itv)
int idx = (itv->pgm_info_write_idx + i) % itv->pgm_info_num;
struct v4l2_enc_idx_entry *e = itv->pgm_info + idx;
u32 addr = itv->pgm_info_offset + 4 + idx * 24;
- const int mapping[] = { V4L2_ENC_IDX_FRAME_P, V4L2_ENC_IDX_FRAME_I, V4L2_ENC_IDX_FRAME_B, 0 };
+ const int mapping[8] = { -1, V4L2_ENC_IDX_FRAME_I, V4L2_ENC_IDX_FRAME_P, -1,
+ V4L2_ENC_IDX_FRAME_B, -1, -1, -1 };
+ // 1=I, 2=P, 4=B
e->offset = read_enc(addr + 4) + ((u64)read_enc(addr + 8) << 32);
if (e->offset > itv->mpg_data_received) {
@@ -199,7 +201,7 @@ static void ivtv_update_pgm_info(struct ivtv *itv)
e->offset += itv->vbi_data_inserted;
e->length = read_enc(addr);
e->pts = read_enc(addr + 16) + ((u64)(read_enc(addr + 20) & 1) << 32);
- e->flags = mapping[read_enc(addr + 12) & 3];
+ e->flags = mapping[read_enc(addr + 12) & 7];
i++;
}
itv->pgm_info_write_idx = (itv->pgm_info_write_idx + i) % itv->pgm_info_num;
diff --git a/drivers/media/video/ivtv/ivtv-ioctl.c b/drivers/media/video/ivtv/ivtv-ioctl.c
index 5977a79619c..dfe0aedc60f 100644
--- a/drivers/media/video/ivtv/ivtv-ioctl.c
+++ b/drivers/media/video/ivtv/ivtv-ioctl.c
@@ -1099,14 +1099,21 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void
case VIDIOC_G_ENC_INDEX: {
struct v4l2_enc_idx *idx = arg;
+ struct v4l2_enc_idx_entry *e = idx->entry;
+ int entries;
int i;
- idx->entries = (itv->pgm_info_write_idx + IVTV_MAX_PGM_INDEX - itv->pgm_info_read_idx) %
+ entries = (itv->pgm_info_write_idx + IVTV_MAX_PGM_INDEX - itv->pgm_info_read_idx) %
IVTV_MAX_PGM_INDEX;
- if (idx->entries > V4L2_ENC_IDX_ENTRIES)
- idx->entries = V4L2_ENC_IDX_ENTRIES;
- for (i = 0; i < idx->entries; i++) {
- idx->entry[i] = itv->pgm_info[(itv->pgm_info_read_idx + i) % IVTV_MAX_PGM_INDEX];
+ if (entries > V4L2_ENC_IDX_ENTRIES)
+ entries = V4L2_ENC_IDX_ENTRIES;
+ idx->entries = 0;
+ for (i = 0; i < entries; i++) {
+ *e = itv->pgm_info[(itv->pgm_info_read_idx + i) % IVTV_MAX_PGM_INDEX];
+ if ((e->flags & V4L2_ENC_IDX_FRAME_MASK) <= V4L2_ENC_IDX_FRAME_B) {
+ idx->entries++;
+ e++;
+ }
}
itv->pgm_info_read_idx = (itv->pgm_info_read_idx + idx->entries) % IVTV_MAX_PGM_INDEX;
break;
diff --git a/drivers/media/video/pwc/pwc-if.c b/drivers/media/video/pwc/pwc-if.c
index 3d81966d8c4..931b274bffc 100644
--- a/drivers/media/video/pwc/pwc-if.c
+++ b/drivers/media/video/pwc/pwc-if.c
@@ -1243,7 +1243,7 @@ static int pwc_video_close(struct inode *inode, struct file *file)
PWC_ERROR("Failed to power down camera (%d)\n", i);
}
pdev->vopen--;
- PWC_DEBUG_OPEN("<< video_close() vopen=%d\n", i);
+ PWC_DEBUG_OPEN("<< video_close() vopen=%d\n", pdev->vopen);
} else {
pwc_cleanup(pdev);
/* Free memory (don't set pdev to 0 just yet) */
diff --git a/drivers/media/video/saa7134/saa7134-cards.c b/drivers/media/video/saa7134/saa7134-cards.c
index 8ec83bd7009..25ec1681081 100644
--- a/drivers/media/video/saa7134/saa7134-cards.c
+++ b/drivers/media/video/saa7134/saa7134-cards.c
@@ -1537,18 +1537,18 @@ struct saa7134_board saa7134_boards[] = {
},{
.name = name_comp1,
.vmux = 0,
- .amux = LINE2,
- .gpio = 0x00,
+ .amux = LINE1,
+ .gpio = 0x02,
},{
.name = name_comp2,
.vmux = 3,
- .amux = LINE2,
- .gpio = 0x00,
+ .amux = LINE1,
+ .gpio = 0x02,
},{
.name = name_svideo,
.vmux = 8,
- .amux = LINE2,
- .gpio = 0x00,
+ .amux = LINE1,
+ .gpio = 0x02,
}},
.radio = {
.name = name_radio,
diff --git a/drivers/media/video/saa7191.c b/drivers/media/video/saa7191.c
index 8615a6081a5..b4018cce328 100644
--- a/drivers/media/video/saa7191.c
+++ b/drivers/media/video/saa7191.c
@@ -130,7 +130,7 @@ static int saa7191_write_reg(struct i2c_client *client, u8 reg,
/* the first byte of data must be the first subaddress number (register) */
static int saa7191_write_block(struct i2c_client *client,
- u8 length, u8 *data)
+ u8 length, const u8 *data)
{
int i;
int ret;
@@ -592,7 +592,7 @@ static int saa7191_attach(struct i2c_adapter *adap, int addr, int kind)
if (err)
goto out_free_decoder;
- err = saa7191_write_block(client, sizeof(initseq), (u8 *)initseq);
+ err = saa7191_write_block(client, sizeof(initseq), initseq);
if (err) {
printk(KERN_ERR "SAA7191 initialization failed\n");
goto out_detach_client;
diff --git a/drivers/media/video/usbvision/usbvision-cards.c b/drivers/media/video/usbvision/usbvision-cards.c
index 380564cd331..f09eb102731 100644
--- a/drivers/media/video/usbvision/usbvision-cards.c
+++ b/drivers/media/video/usbvision/usbvision-cards.c
@@ -1081,6 +1081,7 @@ struct usb_device_id usbvision_table [] = {
{ USB_DEVICE(0x2304, 0x0301), .driver_info=PINNA_LINX_VD_IN_CAB_PAL },
{ USB_DEVICE(0x2304, 0x0419), .driver_info=PINNA_PCTV_BUNGEE_PAL_FM },
{ USB_DEVICE(0x2400, 0x4200), .driver_info=HPG_WINTV },
+ { }, /* terminate list */
};
MODULE_DEVICE_TABLE (usb, usbvision_table);
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index a26655881e6..73e248fb2ff 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -202,25 +202,5 @@ config THINKPAD_ACPI_BAY
If you are not sure, say Y here.
-config THINKPAD_ACPI_INPUT_ENABLED
- bool "Enable input layer support by default"
- depends on THINKPAD_ACPI
- default n
- ---help---
- This option enables thinkpad-acpi hot key handling over the input
- layer at driver load time. When it is unset, the driver does not
- enable hot key handling by default, and also starts up with a mostly
- empty keymap.
-
- This option should be enabled if you have a new enough HAL or other
- userspace support that properly handles the thinkpad-acpi event
- device. It auto-tunes the hot key support to those reported by the
- firmware and enables it automatically.
-
- If unsure, say N here to retain the old behaviour of ibm-acpi, and
- thinkpad-acpi up to kernel 2.6.21: userspace will have to enable and
- set up the thinkpad-acpi hot key handling using the sysfs interace
- after loading the driver.
-
endif # MISC_DEVICES
diff --git a/drivers/misc/msi-laptop.c b/drivers/misc/msi-laptop.c
index 932a415197b..349be934db7 100644
--- a/drivers/misc/msi-laptop.c
+++ b/drivers/misc/msi-laptop.c
@@ -353,7 +353,7 @@ static int __init msi_init(void)
if (IS_ERR(msibl_device))
return PTR_ERR(msibl_device);
- msibl_device->props.max_brightness = MSI_LCD_LEVEL_MAX-1,
+ msibl_device->props.max_brightness = MSI_LCD_LEVEL_MAX-1;
ret = platform_driver_register(&msipf_driver);
if (ret)
diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c
index bb8956d0c10..0222bbaf7b7 100644
--- a/drivers/misc/thinkpad_acpi.c
+++ b/drivers/misc/thinkpad_acpi.c
@@ -21,7 +21,7 @@
* 02110-1301, USA.
*/
-#define IBM_VERSION "0.15"
+#define IBM_VERSION "0.16"
#define TPACPI_SYSFS_VERSION 0x010000
/*
@@ -906,9 +906,26 @@ static ssize_t hotkey_radio_sw_show(struct device *dev,
static struct device_attribute dev_attr_hotkey_radio_sw =
__ATTR(hotkey_radio_sw, S_IRUGO, hotkey_radio_sw_show, NULL);
+/* sysfs hotkey report_mode -------------------------------------------- */
+static ssize_t hotkey_report_mode_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "%d\n",
+ (hotkey_report_mode != 0) ? hotkey_report_mode : 1);
+}
+
+static struct device_attribute dev_attr_hotkey_report_mode =
+ __ATTR(hotkey_report_mode, S_IRUGO, hotkey_report_mode_show, NULL);
+
/* --------------------------------------------------------------------- */
-static struct attribute *hotkey_mask_attributes[] = {
+static struct attribute *hotkey_attributes[] __initdata = {
+ &dev_attr_hotkey_enable.attr,
+ &dev_attr_hotkey_report_mode.attr,
+};
+
+static struct attribute *hotkey_mask_attributes[] __initdata = {
&dev_attr_hotkey_mask.attr,
&dev_attr_hotkey_bios_enabled.attr,
&dev_attr_hotkey_bios_mask.attr,
@@ -987,11 +1004,12 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
str_supported(tp_features.hotkey));
if (tp_features.hotkey) {
- hotkey_dev_attributes = create_attr_set(7, NULL);
+ hotkey_dev_attributes = create_attr_set(8, NULL);
if (!hotkey_dev_attributes)
return -ENOMEM;
- res = add_to_attr_set(hotkey_dev_attributes,
- &dev_attr_hotkey_enable.attr);
+ res = add_many_to_attr_set(hotkey_dev_attributes,
+ hotkey_attributes,
+ ARRAY_SIZE(hotkey_attributes));
if (res)
return res;
@@ -1055,11 +1073,6 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
TPACPI_HOTKEY_MAP_SIZE);
}
-#ifndef CONFIG_THINKPAD_ACPI_INPUT_ENABLED
- for (i = 0; i < 12; i++)
- hotkey_keycode_map[i] = KEY_UNKNOWN;
-#endif /* ! CONFIG_THINKPAD_ACPI_INPUT_ENABLED */
-
set_bit(EV_KEY, tpacpi_inputdev->evbit);
set_bit(EV_MSC, tpacpi_inputdev->evbit);
set_bit(MSC_SCAN, tpacpi_inputdev->mscbit);
@@ -1081,14 +1094,17 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
set_bit(SW_RADIO, tpacpi_inputdev->swbit);
}
-#ifdef CONFIG_THINKPAD_ACPI_INPUT_ENABLED
dbg_printk(TPACPI_DBG_INIT,
"enabling hot key handling\n");
res = hotkey_set(1, (hotkey_all_mask & ~hotkey_reserved_mask)
| hotkey_orig_mask);
if (res)
return res;
-#endif /* CONFIG_THINKPAD_ACPI_INPUT_ENABLED */
+
+ dbg_printk(TPACPI_DBG_INIT,
+ "legacy hot key reporting over procfs %s\n",
+ (hotkey_report_mode < 2) ?
+ "enabled" : "disabled");
}
return (tp_features.hotkey)? 0 : 1;
@@ -1142,58 +1158,65 @@ static void hotkey_notify(struct ibm_struct *ibm, u32 event)
{
u32 hkey;
unsigned int keycode, scancode;
- int sendacpi = 1;
+ int send_acpi_ev = 0;
if (event == 0x80 && acpi_evalf(hkey_handle, &hkey, "MHKP", "d")) {
- if (tpacpi_inputdev->users > 0) {
- switch (hkey >> 12) {
- case 1:
- /* 0x1000-0x1FFF: key presses */
- scancode = hkey & 0xfff;
- if (scancode > 0 && scancode < 0x21) {
- scancode--;
- keycode = hotkey_keycode_map[scancode];
- tpacpi_input_send_key(scancode, keycode);
- sendacpi = (keycode == KEY_RESERVED
- || keycode == KEY_UNKNOWN);
- } else {
- printk(IBM_ERR
- "hotkey 0x%04x out of range for keyboard map\n",
- hkey);
- }
- break;
- case 5:
- /* 0x5000-0x5FFF: LID */
- /* we don't handle it through this path, just
- * eat up known LID events */
- if (hkey != 0x5001 && hkey != 0x5002) {
- printk(IBM_ERR
- "unknown LID-related hotkey event: 0x%04x\n",
- hkey);
- }
+ switch (hkey >> 12) {
+ case 1:
+ /* 0x1000-0x1FFF: key presses */
+ scancode = hkey & 0xfff;
+ if (scancode > 0 && scancode < 0x21) {
+ scancode--;
+ keycode = hotkey_keycode_map[scancode];
+ tpacpi_input_send_key(scancode, keycode);
+ } else {
+ printk(IBM_ERR
+ "hotkey 0x%04x out of range for keyboard map\n",
+ hkey);
+ send_acpi_ev = 1;
+ }
+ break;
+ case 5:
+ /* 0x5000-0x5FFF: LID */
+ /* we don't handle it through this path, just
+ * eat up known LID events */
+ if (hkey != 0x5001 && hkey != 0x5002) {
+ printk(IBM_ERR
+ "unknown LID-related hotkey event: 0x%04x\n",
+ hkey);
+ send_acpi_ev = 1;
+ }
+ break;
+ case 7:
+ /* 0x7000-0x7FFF: misc */
+ if (tp_features.hotkey_wlsw && hkey == 0x7000) {
+ tpacpi_input_send_radiosw();
break;
- case 7:
- /* 0x7000-0x7FFF: misc */
- if (tp_features.hotkey_wlsw && hkey == 0x7000) {
- tpacpi_input_send_radiosw();
- sendacpi = 0;
- break;
- }
- /* fallthrough to default */
- default:
- /* case 2: dock-related */
- /* 0x2305 - T43 waking up due to bay lever eject while aslept */
- /* case 3: ultra-bay related. maybe bay in dock? */
- /* 0x3003 - T43 after wake up by bay lever eject (0x2305) */
- printk(IBM_NOTICE "unhandled hotkey event 0x%04x\n", hkey);
}
+ /* fallthrough to default */
+ default:
+ /* case 2: dock-related */
+ /* 0x2305 - T43 waking up due to bay lever eject while aslept */
+ /* case 3: ultra-bay related. maybe bay in dock? */
+ /* 0x3003 - T43 after wake up by bay lever eject (0x2305) */
+ printk(IBM_NOTICE "unhandled HKEY event 0x%04x\n", hkey);
+ send_acpi_ev = 1;
}
-
- if (sendacpi)
- acpi_bus_generate_proc_event(ibm->acpi->device, event, hkey);
} else {
printk(IBM_ERR "unknown hotkey notification event %d\n", event);
- acpi_bus_generate_proc_event(ibm->acpi->device, event, 0);
+ hkey = 0;
+ send_acpi_ev = 1;
+ }
+
+ /* Legacy events */
+ if (send_acpi_ev || hotkey_report_mode < 2)
+ acpi_bus_generate_proc_event(ibm->acpi->device, event, hkey);
+
+ /* netlink events */
+ if (send_acpi_ev) {
+ acpi_bus_generate_netlink_event(ibm->acpi->device->pnp.device_class,
+ ibm->acpi->device->dev.bus_id,
+ event, hkey);
}
}
@@ -4623,6 +4646,9 @@ module_param_named(fan_control, fan_control_allowed, bool, 0);
static int brightness_mode;
module_param_named(brightness_mode, brightness_mode, int, 0);
+static unsigned int hotkey_report_mode;
+module_param(hotkey_report_mode, uint, 0);
+
#define IBM_PARAM(feature) \
module_param_call(feature, set_ibm_param, NULL, NULL, 0)
@@ -4648,6 +4674,10 @@ static int __init thinkpad_acpi_module_init(void)
{
int ret, i;
+ /* Parameter checking */
+ if (hotkey_report_mode > 2)
+ return -EINVAL;
+
/* Driver-level probe */
get_thinkpad_model_data(&thinkpad_id);
diff --git a/drivers/misc/thinkpad_acpi.h b/drivers/misc/thinkpad_acpi.h
index eee8809a50d..082a1cbc16c 100644
--- a/drivers/misc/thinkpad_acpi.h
+++ b/drivers/misc/thinkpad_acpi.h
@@ -181,6 +181,7 @@ static void tpacpi_remove_driver_attributes(struct device_driver *drv);
static int experimental;
static u32 dbg_level;
static int force_load;
+static unsigned int hotkey_report_mode;
static int thinkpad_acpi_module_init(void);
static void thinkpad_acpi_module_exit(void);
diff --git a/drivers/mtd/nand/cafe_nand.c b/drivers/mtd/nand/cafe_nand.c
index cff969d05d4..6f32a35eb10 100644
--- a/drivers/mtd/nand/cafe_nand.c
+++ b/drivers/mtd/nand/cafe_nand.c
@@ -816,7 +816,8 @@ static void __devexit cafe_nand_remove(struct pci_dev *pdev)
}
static struct pci_device_id cafe_nand_tbl[] = {
- { 0x11ab, 0x4100, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_MEMORY_FLASH << 8, 0xFFFF0 }
+ { 0x11ab, 0x4100, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_MEMORY_FLASH << 8, 0xFFFF0 },
+ { 0, }
};
MODULE_DEVICE_TABLE(pci, cafe_nand_tbl);
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index 5b9e17bf174..c5519250efd 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -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
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index e684212fd8e..9c928a84584 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -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/atl1/atl1_main.c b/drivers/net/atl1/atl1_main.c
index 3c1984ecf36..f23e13c8f9a 100644
--- a/drivers/net/atl1/atl1_main.c
+++ b/drivers/net/atl1/atl1_main.c
@@ -2203,21 +2203,20 @@ static int __devinit atl1_probe(struct pci_dev *pdev,
struct net_device *netdev;
struct atl1_adapter *adapter;
static int cards_found = 0;
- bool pci_using_64 = true;
int err;
err = pci_enable_device(pdev);
if (err)
return err;
- err = pci_set_dma_mask(pdev, DMA_64BIT_MASK);
+ /*
+ * 64-bit DMA currently has data corruption problems, so let's just
+ * use 32-bit DMA for now. This is a big hack that is probably wrong.
+ */
+ err = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
if (err) {
- err = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
- if (err) {
- dev_err(&pdev->dev, "no usable DMA configuration\n");
- goto err_dma;
- }
- pci_using_64 = false;
+ dev_err(&pdev->dev, "no usable DMA configuration\n");
+ goto err_dma;
}
/* Mark all PCI regions associated with PCI device
* pdev as being reserved by owner atl1_driver_name
@@ -2282,7 +2281,6 @@ static int __devinit atl1_probe(struct pci_dev *pdev,
netdev->ethtool_ops = &atl1_ethtool_ops;
adapter->bd_number = cards_found;
- adapter->pci_using_64 = pci_using_64;
/* setup the private structure */
err = atl1_sw_init(adapter);
@@ -2299,9 +2297,6 @@ static int __devinit atl1_probe(struct pci_dev *pdev,
*/
/* netdev->features |= NETIF_F_TSO; */
- if (pci_using_64)
- netdev->features |= NETIF_F_HIGHDMA;
-
netdev->features |= NETIF_F_LLTX;
/*
diff --git a/drivers/net/ehea/ehea.h b/drivers/net/ehea/ehea.h
index d67f97bfa3a..8d58be56f4e 100644
--- a/drivers/net/ehea/ehea.h
+++ b/drivers/net/ehea/ehea.h
@@ -39,7 +39,7 @@
#include <asm/io.h>
#define DRV_NAME "ehea"
-#define DRV_VERSION "EHEA_0073"
+#define DRV_VERSION "EHEA_0074"
/* eHEA capability flags */
#define DLPAR_PORT_ADD_REM 1
@@ -402,6 +402,8 @@ struct ehea_mc_list {
#define EHEA_PORT_UP 1
#define EHEA_PORT_DOWN 0
+#define EHEA_PHY_LINK_UP 1
+#define EHEA_PHY_LINK_DOWN 0
#define EHEA_MAX_PORT_RES 16
struct ehea_port {
struct ehea_adapter *adapter; /* adapter that owns this port */
@@ -427,6 +429,7 @@ struct ehea_port {
u32 msg_enable;
u32 sig_comp_iv;
u32 state;
+ u8 phy_link;
u8 full_duplex;
u8 autoneg;
u8 num_def_qps;
diff --git a/drivers/net/ehea/ehea_main.c b/drivers/net/ehea/ehea_main.c
index db5747490a0..717b12984d1 100644
--- a/drivers/net/ehea/ehea_main.c
+++ b/drivers/net/ehea/ehea_main.c
@@ -53,17 +53,21 @@ static int rq3_entries = EHEA_DEF_ENTRIES_RQ3;
static int sq_entries = EHEA_DEF_ENTRIES_SQ;
static int use_mcs = 0;
static int num_tx_qps = EHEA_NUM_TX_QP;
+static int prop_carrier_state = 0;
module_param(msg_level, int, 0);
module_param(rq1_entries, int, 0);
module_param(rq2_entries, int, 0);
module_param(rq3_entries, int, 0);
module_param(sq_entries, int, 0);
+module_param(prop_carrier_state, int, 0);
module_param(use_mcs, int, 0);
module_param(num_tx_qps, int, 0);
MODULE_PARM_DESC(num_tx_qps, "Number of TX-QPS");
MODULE_PARM_DESC(msg_level, "msg_level");
+MODULE_PARM_DESC(prop_carrier_state, "Propagate carrier state of physical "
+ "port to stack. 1:yes, 0:no. Default = 0 ");
MODULE_PARM_DESC(rq3_entries, "Number of entries for Receive Queue 3 "
"[2^x - 1], x = [6..14]. Default = "
__MODULE_STRING(EHEA_DEF_ENTRIES_RQ3) ")");
@@ -467,7 +471,7 @@ static struct ehea_cqe *ehea_proc_rwqes(struct net_device *dev,
else
netif_receive_skb(skb);
- dev->last_rx = jiffies;
+ port->netdev->last_rx = jiffies;
} else {
pr->p_stats.poll_receive_errors++;
port_reset = ehea_treat_poll_error(pr, rq, cqe,
@@ -814,7 +818,9 @@ int ehea_set_portspeed(struct ehea_port *port, u32 port_speed)
ehea_error("Failed setting port speed");
}
}
- netif_carrier_on(port->netdev);
+ if (!prop_carrier_state || (port->phy_link == EHEA_PHY_LINK_UP))
+ netif_carrier_on(port->netdev);
+
kfree(cb4);
out:
return ret;
@@ -869,13 +875,19 @@ static void ehea_parse_eqe(struct ehea_adapter *adapter, u64 eqe)
}
if (EHEA_BMASK_GET(NEQE_EXTSWITCH_PORT_UP, eqe)) {
+ port->phy_link = EHEA_PHY_LINK_UP;
if (netif_msg_link(port))
ehea_info("%s: Physical port up",
port->netdev->name);
+ if (prop_carrier_state)
+ netif_carrier_on(port->netdev);
} else {
+ port->phy_link = EHEA_PHY_LINK_DOWN;
if (netif_msg_link(port))
ehea_info("%s: Physical port down",
port->netdev->name);
+ if (prop_carrier_state)
+ netif_carrier_off(port->netdev);
}
if (EHEA_BMASK_GET(NEQE_EXTSWITCH_PRIMARY, eqe))
diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c
index 1799eee88db..6a117e9968c 100644
--- a/drivers/net/mv643xx_eth.c
+++ b/drivers/net/mv643xx_eth.c
@@ -1222,7 +1222,7 @@ static int mv643xx_eth_start_xmit(struct sk_buff *skb, struct net_device *dev)
spin_lock_irqsave(&mp->lock, flags);
eth_tx_submit_descs_for_skb(mp, skb);
- stats->tx_bytes = skb->len;
+ stats->tx_bytes += skb->len;
stats->tx_packets++;
dev->trans_start = jiffies;
diff --git a/drivers/net/pcmcia/3c589_cs.c b/drivers/net/pcmcia/3c589_cs.c
index 503f2685fb7..c06cae3f0b5 100644
--- a/drivers/net/pcmcia/3c589_cs.c
+++ b/drivers/net/pcmcia/3c589_cs.c
@@ -116,7 +116,7 @@ struct el3_private {
spinlock_t lock;
};
-static const char *if_names[] = { "auto", "10baseT", "10base2", "AUI" };
+static const char *if_names[] = { "auto", "10base2", "10baseT", "AUI" };
/*====================================================================*/
diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c
index e323efd4ed1..0cc4369cacb 100644
--- a/drivers/net/phy/phy.c
+++ b/drivers/net/phy/phy.c
@@ -755,7 +755,7 @@ out_unlock:
*/
void phy_start(struct phy_device *phydev)
{
- spin_lock(&phydev->lock);
+ spin_lock_bh(&phydev->lock);
switch (phydev->state) {
case PHY_STARTING:
@@ -769,7 +769,7 @@ void phy_start(struct phy_device *phydev)
default:
break;
}
- spin_unlock(&phydev->lock);
+ spin_unlock_bh(&phydev->lock);
}
EXPORT_SYMBOL(phy_stop);
EXPORT_SYMBOL(phy_start);
diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c
index e275df8c55b..49328e05050 100644
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
@@ -644,7 +644,7 @@ static int phy_probe(struct device *dev)
if (!(phydrv->flags & PHY_HAS_INTERRUPT))
phydev->irq = PHY_POLL;
- spin_lock(&phydev->lock);
+ spin_lock_bh(&phydev->lock);
/* Start out supporting everything. Eventually,
* a controller will attach, and may modify one
@@ -658,7 +658,7 @@ static int phy_probe(struct device *dev)
if (phydev->drv->probe)
err = phydev->drv->probe(phydev);
- spin_unlock(&phydev->lock);
+ spin_unlock_bh(&phydev->lock);
return err;
diff --git a/drivers/net/ppp_generic.c b/drivers/net/ppp_generic.c
index 9293c82ef2a..4b49d0e8c7e 100644
--- a/drivers/net/ppp_generic.c
+++ b/drivers/net/ppp_generic.c
@@ -899,17 +899,9 @@ ppp_start_xmit(struct sk_buff *skb, struct net_device *dev)
/* Put the 2-byte PPP protocol number on the front,
making sure there is room for the address and control fields. */
- if (skb_headroom(skb) < PPP_HDRLEN) {
- struct sk_buff *ns;
-
- ns = alloc_skb(skb->len + dev->hard_header_len, GFP_ATOMIC);
- if (ns == 0)
- goto outf;
- skb_reserve(ns, dev->hard_header_len);
- skb_copy_bits(skb, 0, skb_put(ns, skb->len), skb->len);
- kfree_skb(skb);
- skb = ns;
- }
+ if (skb_cow_head(skb, PPP_HDRLEN))
+ goto outf;
+
pp = skb_push(skb, 2);
proto = npindex_to_proto[npi];
pp[0] = proto >> 8;
@@ -1533,7 +1525,7 @@ ppp_input_error(struct ppp_channel *chan, int code)
static void
ppp_receive_frame(struct ppp *ppp, struct sk_buff *skb, struct channel *pch)
{
- if (skb->len >= 2) {
+ if (pskb_may_pull(skb, 2)) {
#ifdef CONFIG_PPP_MULTILINK
/* XXX do channel-level decompression here */
if (PPP_PROTO(skb) == PPP_MP)
@@ -1585,7 +1577,7 @@ ppp_receive_nonmp_frame(struct ppp *ppp, struct sk_buff *skb)
if (ppp->vj == 0 || (ppp->flags & SC_REJ_COMP_TCP))
goto err;
- if (skb_tailroom(skb) < 124) {
+ if (skb_tailroom(skb) < 124 || skb_cloned(skb)) {
/* copy to a new sk_buff with more tailroom */
ns = dev_alloc_skb(skb->len + 128);
if (ns == 0) {
@@ -1656,23 +1648,29 @@ ppp_receive_nonmp_frame(struct ppp *ppp, struct sk_buff *skb)
/* check if the packet passes the pass and active filters */
/* the filter instructions are constructed assuming
a four-byte PPP header on each packet */
- *skb_push(skb, 2) = 0;
- if (ppp->pass_filter
- && sk_run_filter(skb, ppp->pass_filter,
- ppp->pass_len) == 0) {
- if (ppp->debug & 1)
- printk(KERN_DEBUG "PPP: inbound frame not passed\n");
- kfree_skb(skb);
- return;
- }
- if (!(ppp->active_filter
- && sk_run_filter(skb, ppp->active_filter,
- ppp->active_len) == 0))
- ppp->last_recv = jiffies;
- skb_pull(skb, 2);
-#else
- ppp->last_recv = jiffies;
+ if (ppp->pass_filter || ppp->active_filter) {
+ if (skb_cloned(skb) &&
+ pskb_expand_head(skb, 0, 0, GFP_ATOMIC))
+ goto err;
+
+ *skb_push(skb, 2) = 0;
+ if (ppp->pass_filter
+ && sk_run_filter(skb, ppp->pass_filter,
+ ppp->pass_len) == 0) {
+ if (ppp->debug & 1)
+ printk(KERN_DEBUG "PPP: inbound frame "
+ "not passed\n");
+ kfree_skb(skb);
+ return;
+ }
+ if (!(ppp->active_filter
+ && sk_run_filter(skb, ppp->active_filter,
+ ppp->active_len) == 0))
+ ppp->last_recv = jiffies;
+ __skb_pull(skb, 2);
+ } else
#endif /* CONFIG_PPP_FILTER */
+ ppp->last_recv = jiffies;
if ((ppp->dev->flags & IFF_UP) == 0
|| ppp->npmode[npi] != NPMODE_PASS) {
@@ -1770,7 +1768,7 @@ ppp_receive_mp_frame(struct ppp *ppp, struct sk_buff *skb, struct channel *pch)
struct channel *ch;
int mphdrlen = (ppp->flags & SC_MP_SHORTSEQ)? MPHDRLEN_SSN: MPHDRLEN;
- if (!pskb_may_pull(skb, mphdrlen) || ppp->mrru == 0)
+ if (!pskb_may_pull(skb, mphdrlen + 1) || ppp->mrru == 0)
goto err; /* no good, throw it away */
/* Decode sequence number and begin/end bits */
diff --git a/drivers/net/pppoe.c b/drivers/net/pppoe.c
index 68631a5721a..0d7f570b9a5 100644
--- a/drivers/net/pppoe.c
+++ b/drivers/net/pppoe.c
@@ -385,12 +385,12 @@ static int pppoe_rcv(struct sk_buff *skb,
struct pppoe_hdr *ph;
struct pppox_sock *po;
- if (!pskb_may_pull(skb, sizeof(struct pppoe_hdr)))
- goto drop;
-
if (!(skb = skb_share_check(skb, GFP_ATOMIC)))
goto out;
+ if (!pskb_may_pull(skb, sizeof(struct pppoe_hdr)))
+ goto drop;
+
ph = pppoe_hdr(skb);
po = get_item((unsigned long) ph->sid, eth_hdr(skb)->h_source, dev->ifindex);
@@ -848,71 +848,45 @@ static int __pppoe_xmit(struct sock *sk, struct sk_buff *skb)
{
struct pppox_sock *po = pppox_sk(sk);
struct net_device *dev = po->pppoe_dev;
- struct pppoe_hdr hdr;
struct pppoe_hdr *ph;
- int headroom = skb_headroom(skb);
int data_len = skb->len;
- struct sk_buff *skb2;
if (sock_flag(sk, SOCK_DEAD) || !(sk->sk_state & PPPOX_CONNECTED))
goto abort;
- hdr.ver = 1;
- hdr.type = 1;
- hdr.code = 0;
- hdr.sid = po->num;
- hdr.length = htons(skb->len);
-
if (!dev)
goto abort;
- /* Copy the skb if there is no space for the header. */
- if (headroom < (sizeof(struct pppoe_hdr) + dev->hard_header_len)) {
- skb2 = dev_alloc_skb(32+skb->len +
- sizeof(struct pppoe_hdr) +
- dev->hard_header_len);
-
- if (skb2 == NULL)
- goto abort;
-
- skb_reserve(skb2, dev->hard_header_len + sizeof(struct pppoe_hdr));
- skb_copy_from_linear_data(skb, skb_put(skb2, skb->len),
- skb->len);
- } else {
- /* Make a clone so as to not disturb the original skb,
- * give dev_queue_xmit something it can free.
- */
- skb2 = skb_clone(skb, GFP_ATOMIC);
-
- if (skb2 == NULL)
- goto abort;
- }
+ /* Copy the data if there is no space for the header or if it's
+ * read-only.
+ */
+ if (skb_cow_head(skb, sizeof(*ph) + dev->hard_header_len))
+ goto abort;
- ph = (struct pppoe_hdr *) skb_push(skb2, sizeof(struct pppoe_hdr));
- memcpy(ph, &hdr, sizeof(struct pppoe_hdr));
- skb2->protocol = __constant_htons(ETH_P_PPP_SES);
+ __skb_push(skb, sizeof(*ph));
+ skb_reset_network_header(skb);
- skb_reset_network_header(skb2);
+ ph = pppoe_hdr(skb);
+ ph->ver = 1;
+ ph->type = 1;
+ ph->code = 0;
+ ph->sid = po->num;
+ ph->length = htons(data_len);
- skb2->dev = dev;
+ skb->protocol = __constant_htons(ETH_P_PPP_SES);
+ skb->dev = dev;
- dev->hard_header(skb2, dev, ETH_P_PPP_SES,
+ dev->hard_header(skb, dev, ETH_P_PPP_SES,
po->pppoe_pa.remote, NULL, data_len);
- /* We're transmitting skb2, and assuming that dev_queue_xmit
- * will free it. The generic ppp layer however, is expecting
- * that we give back 'skb' (not 'skb2') in case of failure,
- * but free it in case of success.
- */
-
- if (dev_queue_xmit(skb2) < 0)
+ if (dev_queue_xmit(skb) < 0)
goto abort;
- kfree_skb(skb);
return 1;
abort:
- return 0;
+ kfree_skb(skb);
+ return 1;
}
diff --git a/drivers/net/sk98lin/Makefile b/drivers/net/sk98lin/Makefile
new file mode 100644
index 00000000000..afd900d5d73
--- /dev/null
+++ b/drivers/net/sk98lin/Makefile
@@ -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
index 00000000000..4e2dbbf7800
--- /dev/null
+++ b/drivers/net/sk98lin/h/lm80.h
@@ -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
index 00000000000..423ad063d09
--- /dev/null
+++ b/drivers/net/sk98lin/h/skaddr.h
@@ -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
index 00000000000..6e256bd9a28
--- /dev/null
+++ b/drivers/net/sk98lin/h/skcsum.h
@@ -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
index 00000000000..3cba171d74b
--- /dev/null
+++ b/drivers/net/sk98lin/h/skdebug.h
@@ -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
index 00000000000..91b8d4f4590
--- /dev/null
+++ b/drivers/net/sk98lin/h/skdrv1st.h
@@ -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
index 00000000000..3fa67171e83
--- /dev/null
+++ b/drivers/net/sk98lin/h/skdrv2nd.h
@@ -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
index 00000000000..da062f76623
--- /dev/null
+++ b/drivers/net/sk98lin/h/skerror.h
@@ -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
index 00000000000..44fd4c3de81
--- /dev/null
+++ b/drivers/net/sk98lin/h/skgedrv.h
@@ -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
index 00000000000..f6282b7956d
--- /dev/null
+++ b/drivers/net/sk98lin/h/skgehw.h
@@ -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
index 00000000000..e6b0016a695
--- /dev/null
+++ b/drivers/net/sk98lin/h/skgehwt.h
@@ -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
index 00000000000..d9b6f6d8dfe
--- /dev/null
+++ b/drivers/net/sk98lin/h/skgei2c.h
@@ -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
index 00000000000..143e635ec24
--- /dev/null
+++ b/drivers/net/sk98lin/h/skgeinit.h
@@ -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
index 00000000000..ddd304f1a48
--- /dev/null
+++ b/drivers/net/sk98lin/h/skgepnm2.h
@@ -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
index 00000000000..1ed214ccb25
--- /dev/null
+++ b/drivers/net/sk98lin/h/skgepnmi.h
@@ -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
index 00000000000..3eec6274e41
--- /dev/null
+++ b/drivers/net/sk98lin/h/skgesirq.h
@@ -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
index 00000000000..6a63f4a15de
--- /dev/null
+++ b/drivers/net/sk98lin/h/ski2c.h
@@ -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
index 00000000000..2ec40d4fdf6
--- /dev/null
+++ b/drivers/net/sk98lin/h/skqueue.h
@@ -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
index 00000000000..ca75dfdcf2d
--- /dev/null
+++ b/drivers/net/sk98lin/h/skrlmt.h
@@ -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
index 00000000000..04e6d7c1ec3
--- /dev/null
+++ b/drivers/net/sk98lin/h/sktimer.h
@@ -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
index 00000000000..40edc96e105
--- /dev/null
+++ b/drivers/net/sk98lin/h/sktypes.h
@@ -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
index 00000000000..a1a7294828e
--- /dev/null
+++ b/drivers/net/sk98lin/h/skversion.h
@@ -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
index 00000000000..fdd9e48e804
--- /dev/null
+++ b/drivers/net/sk98lin/h/skvpd.h
@@ -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
index 00000000000..7f8e6d0084c
--- /dev/null
+++ b/drivers/net/sk98lin/h/xmac_ii.h
@@ -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
index 00000000000..6e6c56aa6d6
--- /dev/null
+++ b/drivers/net/sk98lin/skaddr.c
@@ -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
index 00000000000..37ce03fb8de
--- /dev/null
+++ b/drivers/net/sk98lin/skdim.c
@@ -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
index 00000000000..5a6da8950fa
--- /dev/null
+++ b/drivers/net/sk98lin/skethtool.c
@@ -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
index 00000000000..7dc9c9ebf5e
--- /dev/null
+++ b/drivers/net/sk98lin/skge.c
@@ -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
index 00000000000..db670993c2d
--- /dev/null
+++ b/drivers/net/sk98lin/skgehwt.c
@@ -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
index 00000000000..67f1d6a5c15
--- /dev/null
+++ b/drivers/net/sk98lin/skgeinit.c
@@ -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
index 00000000000..0a6f67a7a39
--- /dev/null
+++ b/drivers/net/sk98lin/skgemib.c
@@ -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
index 00000000000..b36dd9ac6b2
--- /dev/null
+++ b/drivers/net/sk98lin/skgepnmi.c
@@ -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
index 00000000000..3e7aa49afd0
--- /dev/null
+++ b/drivers/net/sk98lin/skgesirq.c
@@ -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
index 00000000000..79bf57cb532
--- /dev/null
+++ b/drivers/net/sk98lin/ski2c.c
@@ -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
index 00000000000..a204f5bb55d
--- /dev/null
+++ b/drivers/net/sk98lin/sklm80.c
@@ -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
index 00000000000..0275b4f71d9
--- /dev/null
+++ b/drivers/net/sk98lin/skqueue.c
@@ -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
index 00000000000..be8d1ccddf6
--- /dev/null
+++ b/drivers/net/sk98lin/skrlmt.c
@@ -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
index 00000000000..4e462955ecd
--- /dev/null
+++ b/drivers/net/sk98lin/sktimer.c
@@ -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
index 00000000000..1e662aaebf8
--- /dev/null
+++ b/drivers/net/sk98lin/skvpd.c
@@ -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
index 00000000000..b4e75022a65
--- /dev/null
+++ b/drivers/net/sk98lin/skxmac2.c
@@ -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 */
diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c
index e6d937ec688..5d812de65d9 100644
--- a/drivers/net/sky2.c
+++ b/drivers/net/sky2.c
@@ -149,6 +149,8 @@ static const char *yukon2_name[] = {
"FE", /* 0xb7 */
};
+static void sky2_set_multicast(struct net_device *dev);
+
/* Access to external PHY */
static int gm_phy_write(struct sky2_hw *hw, unsigned port, u16 reg, u16 val)
{
@@ -2900,8 +2902,10 @@ static int sky2_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
sky2->autoneg = ecmd->autoneg;
sky2->advertising = ecmd->advertising;
- if (netif_running(dev))
+ if (netif_running(dev)) {
sky2_phy_reinit(sky2);
+ sky2_set_multicast(dev);
+ }
return 0;
}
@@ -2994,6 +2998,7 @@ static int sky2_nway_reset(struct net_device *dev)
return -EINVAL;
sky2_phy_reinit(sky2);
+ sky2_set_multicast(dev);
return 0;
}
@@ -4171,6 +4176,8 @@ static int sky2_resume(struct pci_dev *pdev)
dev_close(dev);
goto out;
}
+
+ sky2_set_multicast(dev);
}
}
diff --git a/drivers/net/spider_net.c b/drivers/net/spider_net.c
index 590b12c7246..82d837ab4db 100644
--- a/drivers/net/spider_net.c
+++ b/drivers/net/spider_net.c
@@ -1441,17 +1441,14 @@ static void
spider_net_handle_error_irq(struct spider_net_card *card, u32 status_reg)
{
u32 error_reg1, error_reg2;
- u32 mask_reg1, mask_reg2;
u32 i;
int show_error = 1;
error_reg1 = spider_net_read_reg(card, SPIDER_NET_GHIINT1STS);
error_reg2 = spider_net_read_reg(card, SPIDER_NET_GHIINT2STS);
- mask_reg1 = spider_net_read_reg(card, SPIDER_NET_GHIINT1MSK);
- mask_reg2 = spider_net_read_reg(card,SPIDER_NET_GHIINT2MSK);
- error_reg1 &= mask_reg1;
- error_reg2 &= mask_reg2;
+ error_reg1 &= SPIDER_NET_INT1_MASK_VALUE;
+ error_reg2 &= SPIDER_NET_INT2_MASK_VALUE;
/* check GHIINT0STS ************************************/
if (status_reg)
@@ -1679,11 +1676,10 @@ spider_net_interrupt(int irq, void *ptr)
{
struct net_device *netdev = ptr;
struct spider_net_card *card = netdev_priv(netdev);
- u32 status_reg, mask_reg;
+ u32 status_reg;
status_reg = spider_net_read_reg(card, SPIDER_NET_GHIINT0STS);
- mask_reg = spider_net_read_reg(card, SPIDER_NET_GHIINT0MSK);
- status_reg &= mask_reg;
+ status_reg &= SPIDER_NET_INT0_MASK_VALUE;
if (!status_reg)
return IRQ_NONE;
diff --git a/drivers/net/ucc_geth.c b/drivers/net/ucc_geth.c
index 12e01b24105..9a38dfe45f8 100644
--- a/drivers/net/ucc_geth.c
+++ b/drivers/net/ucc_geth.c
@@ -2148,7 +2148,7 @@ static void ucc_geth_memclean(struct ucc_geth_private *ugeth)
for (j = 0; j < ugeth->ug_info->bdRingLenTx[i]; j++) {
if (ugeth->tx_skbuff[i][j]) {
dma_unmap_single(NULL,
- ((qe_bd_t *)bd)->buf,
+ ((struct qe_bd *)bd)->buf,
(in_be32((u32 *)bd) &
BD_LENGTH_MASK),
DMA_TO_DEVICE);
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c
index c5d6753a55e..dfbd01eaaf3 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c
@@ -3183,6 +3183,9 @@ static void bcm43xx_periodic_work_handler(struct work_struct *work)
unsigned long orig_trans_start = 0;
mutex_lock(&bcm->mutex);
+ /* keep from doing and rearming periodic work if shutting down */
+ if (bcm43xx_status(bcm) == BCM43xx_STAT_UNINIT)
+ goto unlock_mutex;
if (unlikely(bcm->periodic_state % 60 == 0)) {
/* Periodic work will take a long time, so we want it to
* be preemtible.
@@ -3228,14 +3231,10 @@ static void bcm43xx_periodic_work_handler(struct work_struct *work)
mmiowb();
bcm->periodic_state++;
spin_unlock_irqrestore(&bcm->irq_lock, flags);
+unlock_mutex:
mutex_unlock(&bcm->mutex);
}
-void bcm43xx_periodic_tasks_delete(struct bcm43xx_private *bcm)
-{
- cancel_rearming_delayed_work(&bcm->periodic_work);
-}
-
void bcm43xx_periodic_tasks_setup(struct bcm43xx_private *bcm)
{
struct delayed_work *work = &bcm->periodic_work;
@@ -3285,6 +3284,14 @@ static int bcm43xx_rng_init(struct bcm43xx_private *bcm)
return err;
}
+void bcm43xx_cancel_work(struct bcm43xx_private *bcm)
+{
+ /* The system must be unlocked when this routine is entered.
+ * If not, the next 2 steps may deadlock */
+ cancel_work_sync(&bcm->restart_work);
+ cancel_delayed_work_sync(&bcm->periodic_work);
+}
+
static int bcm43xx_shutdown_all_wireless_cores(struct bcm43xx_private *bcm)
{
int ret = 0;
@@ -3321,7 +3328,12 @@ static void bcm43xx_free_board(struct bcm43xx_private *bcm)
{
bcm43xx_rng_exit(bcm);
bcm43xx_sysfs_unregister(bcm);
- bcm43xx_periodic_tasks_delete(bcm);
+
+ mutex_lock(&(bcm)->mutex);
+ bcm43xx_set_status(bcm, BCM43xx_STAT_UNINIT);
+ mutex_unlock(&(bcm)->mutex);
+
+ bcm43xx_cancel_work(bcm);
mutex_lock(&(bcm)->mutex);
bcm43xx_shutdown_all_wireless_cores(bcm);
@@ -4016,7 +4028,7 @@ static int bcm43xx_net_stop(struct net_device *net_dev)
err = bcm43xx_disable_interrupts_sync(bcm);
assert(!err);
bcm43xx_free_board(bcm);
- flush_scheduled_work();
+ bcm43xx_cancel_work(bcm);
return 0;
}
@@ -4148,9 +4160,9 @@ static void bcm43xx_chip_reset(struct work_struct *work)
struct bcm43xx_phyinfo *phy;
int err = -ENODEV;
+ bcm43xx_cancel_work(bcm);
mutex_lock(&(bcm)->mutex);
if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED) {
- bcm43xx_periodic_tasks_delete(bcm);
phy = bcm43xx_current_phy(bcm);
err = bcm43xx_select_wireless_core(bcm, phy->type);
if (!err)
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.h b/drivers/net/wireless/bcm43xx/bcm43xx_main.h
index c8f3c532bab..14cfbeb582e 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_main.h
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.h
@@ -122,7 +122,7 @@ void bcm43xx_wireless_core_reset(struct bcm43xx_private *bcm, int connect_phy);
void bcm43xx_mac_suspend(struct bcm43xx_private *bcm);
void bcm43xx_mac_enable(struct bcm43xx_private *bcm);
-void bcm43xx_periodic_tasks_delete(struct bcm43xx_private *bcm);
+void bcm43xx_cancel_work(struct bcm43xx_private *bcm);
void bcm43xx_periodic_tasks_setup(struct bcm43xx_private *bcm);
void bcm43xx_controller_restart(struct bcm43xx_private *bcm, const char *reason);
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c b/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c
index c71b998a369..8ab5f93d192 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c
@@ -327,7 +327,7 @@ static ssize_t bcm43xx_attr_phymode_store(struct device *dev,
goto out;
}
- bcm43xx_periodic_tasks_delete(bcm);
+ bcm43xx_cancel_work(bcm);
mutex_lock(&(bcm)->mutex);
err = bcm43xx_select_wireless_core(bcm, phytype);
if (!err)
diff --git a/drivers/rtc/rtc-ds1553.c b/drivers/rtc/rtc-ds1553.c
index 46da5714932..5ab3492817d 100644
--- a/drivers/rtc/rtc-ds1553.c
+++ b/drivers/rtc/rtc-ds1553.c
@@ -61,7 +61,7 @@
struct rtc_plat_data {
struct rtc_device *rtc;
void __iomem *ioaddr;
- unsigned long baseaddr;
+ resource_size_t baseaddr;
unsigned long last_jiffies;
int irq;
unsigned int irqen;
diff --git a/drivers/rtc/rtc-ds1742.c b/drivers/rtc/rtc-ds1742.c
index b2e5481ba3b..67291b0f828 100644
--- a/drivers/rtc/rtc-ds1742.c
+++ b/drivers/rtc/rtc-ds1742.c
@@ -55,7 +55,7 @@ struct rtc_plat_data {
void __iomem *ioaddr_rtc;
size_t size_nvram;
size_t size;
- unsigned long baseaddr;
+ resource_size_t baseaddr;
unsigned long last_jiffies;
};
diff --git a/drivers/serial/sunsab.c b/drivers/serial/sunsab.c
index bca57bb9493..e348ba68405 100644
--- a/drivers/serial/sunsab.c
+++ b/drivers/serial/sunsab.c
@@ -58,6 +58,7 @@ struct uart_sunsab_port {
unsigned char interrupt_mask1;/* ISR1 masking */
unsigned char pvr_dtr_bit; /* Which PVR bit is DTR */
unsigned char pvr_dsr_bit; /* Which PVR bit is DSR */
+ unsigned int gis_shift;
int type; /* SAB82532 version */
/* Setting configuration bits while the transmitter is active
@@ -305,13 +306,15 @@ static irqreturn_t sunsab_interrupt(int irq, void *dev_id)
struct tty_struct *tty;
union sab82532_irq_status status;
unsigned long flags;
+ unsigned char gis;
spin_lock_irqsave(&up->port.lock, flags);
status.stat = 0;
- if (readb(&up->regs->r.gis) & SAB82532_GIS_ISA0)
+ gis = readb(&up->regs->r.gis) >> up->gis_shift;
+ if (gis & 1)
status.sreg.isr0 = readb(&up->regs->r.isr0);
- if (readb(&up->regs->r.gis) & SAB82532_GIS_ISA1)
+ if (gis & 2)
status.sreg.isr1 = readb(&up->regs->r.isr1);
tty = NULL;
@@ -327,35 +330,6 @@ static irqreturn_t sunsab_interrupt(int irq, void *dev_id)
transmit_chars(up, &status);
}
- spin_unlock(&up->port.lock);
-
- if (tty)
- tty_flip_buffer_push(tty);
-
- up++;
-
- spin_lock(&up->port.lock);
-
- status.stat = 0;
- if (readb(&up->regs->r.gis) & SAB82532_GIS_ISB0)
- status.sreg.isr0 = readb(&up->regs->r.isr0);
- if (readb(&up->regs->r.gis) & SAB82532_GIS_ISB1)
- status.sreg.isr1 = readb(&up->regs->r.isr1);
-
- tty = NULL;
- if (status.stat) {
- if ((status.sreg.isr0 & (SAB82532_ISR0_TCD | SAB82532_ISR0_TIME |
- SAB82532_ISR0_RFO | SAB82532_ISR0_RPF)) ||
- (status.sreg.isr1 & SAB82532_ISR1_BRK))
-
- tty = receive_chars(up, &status);
- if ((status.sreg.isr0 & SAB82532_ISR0_CDSC) ||
- (status.sreg.isr1 & (SAB82532_ISR1_BRK | SAB82532_ISR1_CSC)))
- check_status(up, &status);
- if (status.sreg.isr1 & (SAB82532_ISR1_ALLS | SAB82532_ISR1_XPR))
- transmit_chars(up, &status);
- }
-
spin_unlock_irqrestore(&up->port.lock, flags);
if (tty)
@@ -539,6 +513,10 @@ static int sunsab_startup(struct uart_port *port)
struct uart_sunsab_port *up = (struct uart_sunsab_port *) port;
unsigned long flags;
unsigned char tmp;
+ int err = request_irq(up->port.irq, sunsab_interrupt,
+ IRQF_SHARED, "sab", up);
+ if (err)
+ return err;
spin_lock_irqsave(&up->port.lock, flags);
@@ -641,6 +619,7 @@ static void sunsab_shutdown(struct uart_port *port)
#endif
spin_unlock_irqrestore(&up->port.lock, flags);
+ free_irq(up->port.irq, up);
}
/*
@@ -1008,9 +987,11 @@ static int __devinit sunsab_init_one(struct uart_sunsab_port *up,
if ((up->port.line & 0x1) == 0) {
up->pvr_dsr_bit = (1 << 0);
up->pvr_dtr_bit = (1 << 1);
+ up->gis_shift = 2;
} else {
up->pvr_dsr_bit = (1 << 3);
up->pvr_dtr_bit = (1 << 2);
+ up->gis_shift = 0;
}
up->cached_pvr = (1 << 1) | (1 << 2) | (1 << 4);
writeb(up->cached_pvr, &up->regs->w.pvr);
@@ -1023,19 +1004,6 @@ static int __devinit sunsab_init_one(struct uart_sunsab_port *up,
up->tec_timeout = SAB82532_MAX_TEC_TIMEOUT;
up->cec_timeout = SAB82532_MAX_CEC_TIMEOUT;
- if (!(up->port.line & 0x01)) {
- int err;
-
- err = request_irq(up->port.irq, sunsab_interrupt,
- IRQF_SHARED, "sab", up);
- if (err) {
- of_iounmap(&op->resource[0],
- up->port.membase,
- sizeof(union sab82532_async_regs));
- return err;
- }
- }
-
return 0;
}
@@ -1051,52 +1019,60 @@ static int __devinit sab_probe(struct of_device *op, const struct of_device_id *
0,
(inst * 2) + 0);
if (err)
- return err;
+ goto out;
err = sunsab_init_one(&up[1], op,
sizeof(union sab82532_async_regs),
(inst * 2) + 1);
- if (err) {
- of_iounmap(&op->resource[0],
- up[0].port.membase,
- sizeof(union sab82532_async_regs));
- free_irq(up[0].port.irq, &up[0]);
- return err;
- }
+ if (err)
+ goto out1;
sunserial_console_match(SUNSAB_CONSOLE(), op->node,
&sunsab_reg, up[0].port.line);
- uart_add_one_port(&sunsab_reg, &up[0].port);
sunserial_console_match(SUNSAB_CONSOLE(), op->node,
&sunsab_reg, up[1].port.line);
- uart_add_one_port(&sunsab_reg, &up[1].port);
+
+ err = uart_add_one_port(&sunsab_reg, &up[0].port);
+ if (err)
+ goto out2;
+
+ err = uart_add_one_port(&sunsab_reg, &up[1].port);
+ if (err)
+ goto out3;
dev_set_drvdata(&op->dev, &up[0]);
inst++;
return 0;
-}
-
-static void __devexit sab_remove_one(struct uart_sunsab_port *up)
-{
- struct of_device *op = to_of_device(up->port.dev);
- uart_remove_one_port(&sunsab_reg, &up->port);
- if (!(up->port.line & 1))
- free_irq(up->port.irq, up);
+out3:
+ uart_remove_one_port(&sunsab_reg, &up[0].port);
+out2:
of_iounmap(&op->resource[0],
- up->port.membase,
+ up[1].port.membase,
sizeof(union sab82532_async_regs));
+out1:
+ of_iounmap(&op->resource[0],
+ up[0].port.membase,
+ sizeof(union sab82532_async_regs));
+out:
+ return err;
}
static int __devexit sab_remove(struct of_device *op)
{
struct uart_sunsab_port *up = dev_get_drvdata(&op->dev);
- sab_remove_one(&up[0]);
- sab_remove_one(&up[1]);
+ uart_remove_one_port(&sunsab_reg, &up[1].port);
+ uart_remove_one_port(&sunsab_reg, &up[0].port);
+ of_iounmap(&op->resource[0],
+ up[1].port.membase,
+ sizeof(union sab82532_async_regs));
+ of_iounmap(&op->resource[0],
+ up[0].port.membase,
+ sizeof(union sab82532_async_regs));
dev_set_drvdata(&op->dev, NULL);
@@ -1143,6 +1119,7 @@ static int __init sunsab_init(void)
sunsab_reg.minor = sunserial_current_minor;
sunsab_reg.nr = num_channels;
+ sunsab_reg.cons = SUNSAB_CONSOLE();
err = uart_register_driver(&sunsab_reg);
if (err) {
diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c
index 7f17d0fd76c..ebf3dc20110 100644
--- a/drivers/usb/core/quirks.c
+++ b/drivers/usb/core/quirks.c
@@ -152,4 +152,10 @@ void usb_detect_quirks(struct usb_device *udev)
/* do any special quirk handling here if needed */
if (udev->quirks & USB_QUIRK_NO_AUTOSUSPEND)
usb_autosuspend_quirk(udev);
+
+ /* By default, disable autosuspend for all non-hubs */
+#ifdef CONFIG_USB_SUSPEND
+ if (udev->descriptor.bDeviceClass != USB_CLASS_HUB)
+ udev->autosuspend_delay = -1;
+#endif
}
diff --git a/drivers/usb/storage/scsiglue.c b/drivers/usb/storage/scsiglue.c
index 47e56079925..1ba19eaa197 100644
--- a/drivers/usb/storage/scsiglue.c
+++ b/drivers/usb/storage/scsiglue.c
@@ -285,15 +285,10 @@ static int device_reset(struct scsi_cmnd *srb)
US_DEBUGP("%s called\n", __FUNCTION__);
- result = usb_autopm_get_interface(us->pusb_intf);
- if (result == 0) {
-
- /* lock the device pointers and do the reset */
- mutex_lock(&(us->dev_mutex));
- result = us->transport_reset(us);
- mutex_unlock(&us->dev_mutex);
- usb_autopm_put_interface(us->pusb_intf);
- }
+ /* lock the device pointers and do the reset */
+ mutex_lock(&(us->dev_mutex));
+ result = us->transport_reset(us);
+ mutex_unlock(&us->dev_mutex);
return result < 0 ? FAILED : SUCCESS;
}
diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c
index 25e557d4fe6..59181667066 100644
--- a/drivers/usb/storage/usb.c
+++ b/drivers/usb/storage/usb.c
@@ -184,14 +184,16 @@ static int storage_suspend(struct usb_interface *iface, pm_message_t message)
{
struct us_data *us = usb_get_intfdata(iface);
- US_DEBUGP("%s\n", __FUNCTION__);
-
/* Wait until no command is running */
mutex_lock(&us->dev_mutex);
+ US_DEBUGP("%s\n", __FUNCTION__);
if (us->suspend_resume_hook)
(us->suspend_resume_hook)(us, US_SUSPEND);
+ /* When runtime PM is working, we'll set a flag to indicate
+ * whether we should autoresume when a SCSI request arrives. */
+
mutex_unlock(&us->dev_mutex);
return 0;
}
@@ -200,11 +202,13 @@ static int storage_resume(struct usb_interface *iface)
{
struct us_data *us = usb_get_intfdata(iface);
- US_DEBUGP("%s\n", __FUNCTION__);
+ mutex_lock(&us->dev_mutex);
+ US_DEBUGP("%s\n", __FUNCTION__);
if (us->suspend_resume_hook)
(us->suspend_resume_hook)(us, US_RESUME);
+ mutex_unlock(&us->dev_mutex);
return 0;
}
@@ -302,7 +306,6 @@ static int usb_stor_control_thread(void * __us)
{
struct us_data *us = (struct us_data *)__us;
struct Scsi_Host *host = us_to_host(us);
- int autopm_rc;
for(;;) {
US_DEBUGP("*** thread sleeping.\n");
@@ -311,9 +314,6 @@ static int usb_stor_control_thread(void * __us)
US_DEBUGP("*** thread awakened.\n");
- /* Autoresume the device */
- autopm_rc = usb_autopm_get_interface(us->pusb_intf);
-
/* lock the device pointers */
mutex_lock(&(us->dev_mutex));
@@ -372,12 +372,6 @@ static int usb_stor_control_thread(void * __us)
us->srb->result = SAM_STAT_GOOD;
}
- /* Did the autoresume fail? */
- else if (autopm_rc < 0) {
- US_DEBUGP("Could not wake device\n");
- us->srb->result = DID_ERROR << 16;
- }
-
/* we've got a command, let's do it! */
else {
US_DEBUG(usb_stor_show_command(us->srb));
@@ -420,10 +414,6 @@ SkipForAbort:
/* unlock the device pointers */
mutex_unlock(&us->dev_mutex);
-
- /* Start an autosuspend */
- if (autopm_rc == 0)
- usb_autopm_put_interface(us->pusb_intf);
} /* for (;;) */
/* Wait until we are told to stop */
@@ -941,7 +931,6 @@ retry:
/* Should we unbind if no devices were detected? */
}
- usb_autopm_put_interface(us->pusb_intf);
complete_and_exit(&us->scanning_done, 0);
}
@@ -1027,7 +1016,6 @@ static int storage_probe(struct usb_interface *intf,
goto BadDevice;
}
- usb_autopm_get_interface(intf); /* dropped in the scanning thread */
wake_up_process(th);
return 0;
@@ -1065,7 +1053,6 @@ static struct usb_driver usb_storage_driver = {
.pre_reset = storage_pre_reset,
.post_reset = storage_post_reset,
.id_table = storage_usb_ids,
- .supports_autosuspend = 1,
};
static int __init usb_stor_init(void)
diff --git a/drivers/video/aty/ati_ids.h b/drivers/video/aty/ati_ids.h
index 685a754991c..dca2eb8f2dd 100644
--- a/drivers/video/aty/ati_ids.h
+++ b/drivers/video/aty/ati_ids.h
@@ -192,6 +192,12 @@
#define PCI_CHIP_RS300_5835 0x5835
#define PCI_CHIP_RS300_5836 0x5836
#define PCI_CHIP_RS300_5837 0x5837
+#define PCI_CHIP_RS480_5955 0x5955
+#define PCI_CHIP_RV280_5960 0x5960
+#define PCI_CHIP_RV280_5961 0x5961
+#define PCI_CHIP_RV280_5962 0x5962
+#define PCI_CHIP_RV280_5964 0x5964
+#define PCI_CHIP_RS482_5975 0x5975
#define PCI_CHIP_RV370_5B60 0x5B60
#define PCI_CHIP_RV370_5B61 0x5B61
#define PCI_CHIP_RV370_5B62 0x5B62
@@ -200,14 +206,8 @@
#define PCI_CHIP_RV370_5B65 0x5B65
#define PCI_CHIP_RV370_5B66 0x5B66
#define PCI_CHIP_RV370_5B67 0x5B67
-#define PCI_CHIP_RV280_5960 0x5960
-#define PCI_CHIP_RV280_5961 0x5961
-#define PCI_CHIP_RV280_5962 0x5962
-#define PCI_CHIP_RV280_5964 0x5964
-#define PCI_CHIP_RS485_5975 0x5975
#define PCI_CHIP_RV280_5C61 0x5C61
#define PCI_CHIP_RV280_5C63 0x5C63
#define PCI_CHIP_R423_5D57 0x5D57
#define PCI_CHIP_RS350_7834 0x7834
#define PCI_CHIP_RS350_7835 0x7835
-#define PCI_CHIP_RS480_5955 0x5955
diff --git a/drivers/video/aty/radeon_base.c b/drivers/video/aty/radeon_base.c
index 47ca62fe7c3..4b747bdaeea 100644
--- a/drivers/video/aty/radeon_base.c
+++ b/drivers/video/aty/radeon_base.c
@@ -102,6 +102,7 @@
static struct pci_device_id radeonfb_pci_table[] = {
/* Radeon Xpress 200m */
CHIP_DEF(PCI_CHIP_RS480_5955, RS480, CHIP_HAS_CRTC2 | CHIP_IS_IGP | CHIP_IS_MOBILITY),
+ CHIP_DEF(PCI_CHIP_RS482_5975, RS480, CHIP_HAS_CRTC2 | CHIP_IS_IGP | CHIP_IS_MOBILITY),
/* Mobility M6 */
CHIP_DEF(PCI_CHIP_RADEON_LY, RV100, CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY),
CHIP_DEF(PCI_CHIP_RADEON_LZ, RV100, CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY),
@@ -153,8 +154,6 @@ static struct pci_device_id radeonfb_pci_table[] = {
/* Mobility 9200 (M9+) */
CHIP_DEF(PCI_CHIP_RV280_5C61, RV280, CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY),
CHIP_DEF(PCI_CHIP_RV280_5C63, RV280, CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY),
- /*Mobility Xpress 200 */
- CHIP_DEF(PCI_CHIP_RS485_5975, R300, CHIP_HAS_CRTC2 | CHIP_IS_IGP | CHIP_IS_MOBILITY),
/* 9200 */
CHIP_DEF(PCI_CHIP_RV280_5960, RV280, CHIP_HAS_CRTC2),
CHIP_DEF(PCI_CHIP_RV280_5961, RV280, CHIP_HAS_CRTC2),
@@ -1285,7 +1284,8 @@ static void radeon_write_pll_regs(struct radeonfb_info *rinfo, struct radeon_reg
if (rinfo->family == CHIP_FAMILY_R300 ||
rinfo->family == CHIP_FAMILY_RS300 ||
rinfo->family == CHIP_FAMILY_R350 ||
- rinfo->family == CHIP_FAMILY_RV350) {
+ rinfo->family == CHIP_FAMILY_RV350 ||
+ rinfo->family == CHIP_FAMILY_RV380 ) {
if (mode->ppll_ref_div & R300_PPLL_REF_DIV_ACC_MASK) {
/* When restoring console mode, use saved PPLL_REF_DIV
* setting.
diff --git a/drivers/video/intelfb/intelfbhw.c b/drivers/video/intelfb/intelfbhw.c
index b21d0dec928..6a47682d861 100644
--- a/drivers/video/intelfb/intelfbhw.c
+++ b/drivers/video/intelfb/intelfbhw.c
@@ -1352,7 +1352,7 @@ intelfbhw_program_mode(struct intelfb_info *dinfo,
/* turn off PLL */
tmp = INREG(dpll_reg);
- dpll_reg &= ~DPLL_VCO_ENABLE;
+ tmp &= ~DPLL_VCO_ENABLE;
OUTREG(dpll_reg, tmp);
/* Set PLL parameters */
diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c
index a6c9078af12..5a5b7116cef 100644
--- a/fs/compat_ioctl.c
+++ b/fs/compat_ioctl.c
@@ -2311,8 +2311,10 @@ static int do_wireless_ioctl(unsigned int fd, unsigned int cmd, unsigned long ar
struct iwreq __user *iwr_u;
struct iw_point __user *iwp;
struct compat_iw_point __user *iwp_u;
- compat_caddr_t pointer;
+ compat_caddr_t pointer_u;
+ void __user *pointer;
__u16 length, flags;
+ int ret;
iwr_u = compat_ptr(arg);
iwp_u = (struct compat_iw_point __user *) &iwr_u->u.data;
@@ -2330,17 +2332,29 @@ static int do_wireless_ioctl(unsigned int fd, unsigned int cmd, unsigned long ar
sizeof(iwr->ifr_ifrn.ifrn_name)))
return -EFAULT;
- if (__get_user(pointer, &iwp_u->pointer) ||
+ if (__get_user(pointer_u, &iwp_u->pointer) ||
__get_user(length, &iwp_u->length) ||
__get_user(flags, &iwp_u->flags))
return -EFAULT;
- if (__put_user(compat_ptr(pointer), &iwp->pointer) ||
+ if (__put_user(compat_ptr(pointer_u), &iwp->pointer) ||
__put_user(length, &iwp->length) ||
__put_user(flags, &iwp->flags))
return -EFAULT;
- return sys_ioctl(fd, cmd, (unsigned long) iwr);
+ ret = sys_ioctl(fd, cmd, (unsigned long) iwr);
+
+ if (__get_user(pointer, &iwp->pointer) ||
+ __get_user(length, &iwp->length) ||
+ __get_user(flags, &iwp->flags))
+ return -EFAULT;
+
+ if (__put_user(ptr_to_compat(pointer), &iwp_u->pointer) ||
+ __put_user(length, &iwp_u->length) ||
+ __put_user(flags, &iwp_u->flags))
+ return -EFAULT;
+
+ return ret;
}
/* Since old style bridge ioctl's endup using SIOCDEVPRIVATE
diff --git a/fs/ext3/namei.c b/fs/ext3/namei.c
index 1586807b817..c1fa1908dba 100644
--- a/fs/ext3/namei.c
+++ b/fs/ext3/namei.c
@@ -140,7 +140,8 @@ struct dx_frame
struct dx_map_entry
{
u32 hash;
- u32 offs;
+ u16 offs;
+ u16 size;
};
#ifdef CONFIG_EXT3_INDEX
@@ -379,13 +380,28 @@ dx_probe(struct dentry *dentry, struct inode *dir,
entries = (struct dx_entry *) (((char *)&root->info) +
root->info.info_length);
- assert(dx_get_limit(entries) == dx_root_limit(dir,
- root->info.info_length));
+
+ if (dx_get_limit(entries) != dx_root_limit(dir,
+ root->info.info_length)) {
+ ext3_warning(dir->i_sb, __FUNCTION__,
+ "dx entry: limit != root limit");
+ brelse(bh);
+ *err = ERR_BAD_DX_DIR;
+ goto fail;
+ }
+
dxtrace (printk("Look up %x", hash));
while (1)
{
count = dx_get_count(entries);
- assert (count && count <= dx_get_limit(entries));
+ if (!count || count > dx_get_limit(entries)) {
+ ext3_warning(dir->i_sb, __FUNCTION__,
+ "dx entry: no count or count > limit");
+ brelse(bh);
+ *err = ERR_BAD_DX_DIR;
+ goto fail2;
+ }
+
p = entries + 1;
q = entries + count - 1;
while (p <= q)
@@ -423,8 +439,15 @@ dx_probe(struct dentry *dentry, struct inode *dir,
if (!(bh = ext3_bread (NULL,dir, dx_get_block(at), 0, err)))
goto fail2;
at = entries = ((struct dx_node *) bh->b_data)->entries;
- assert (dx_get_limit(entries) == dx_node_limit (dir));
+ if (dx_get_limit(entries) != dx_node_limit (dir)) {
+ ext3_warning(dir->i_sb, __FUNCTION__,
+ "dx entry: limit != node limit");
+ brelse(bh);
+ *err = ERR_BAD_DX_DIR;
+ goto fail2;
+ }
frame++;
+ frame->bh = NULL;
}
fail2:
while (frame >= frame_in) {
@@ -432,6 +455,10 @@ fail2:
frame--;
}
fail:
+ if (*err == ERR_BAD_DX_DIR)
+ ext3_warning(dir->i_sb, __FUNCTION__,
+ "Corrupt dir inode %ld, running e2fsck is "
+ "recommended.", dir->i_ino);
return NULL;
}
@@ -671,6 +698,10 @@ errout:
* Directory block splitting, compacting
*/
+/*
+ * Create map of hash values, offsets, and sizes, stored at end of block.
+ * Returns number of entries mapped.
+ */
static int dx_make_map (struct ext3_dir_entry_2 *de, int size,
struct dx_hash_info *hinfo, struct dx_map_entry *map_tail)
{
@@ -684,7 +715,8 @@ static int dx_make_map (struct ext3_dir_entry_2 *de, int size,
ext3fs_dirhash(de->name, de->name_len, &h);
map_tail--;
map_tail->hash = h.hash;
- map_tail->offs = (u32) ((char *) de - base);
+ map_tail->offs = (u16) ((char *) de - base);
+ map_tail->size = le16_to_cpu(de->rec_len);
count++;
cond_resched();
}
@@ -694,6 +726,7 @@ static int dx_make_map (struct ext3_dir_entry_2 *de, int size,
return count;
}
+/* Sort map by hash value */
static void dx_sort_map (struct dx_map_entry *map, unsigned count)
{
struct dx_map_entry *p, *q, *top = map + count - 1;
@@ -1091,6 +1124,10 @@ static inline void ext3_set_de_type(struct super_block *sb,
}
#ifdef CONFIG_EXT3_INDEX
+/*
+ * Move count entries from end of map between two memory locations.
+ * Returns pointer to last entry moved.
+ */
static struct ext3_dir_entry_2 *
dx_move_dirents(char *from, char *to, struct dx_map_entry *map, int count)
{
@@ -1109,6 +1146,10 @@ dx_move_dirents(char *from, char *to, struct dx_map_entry *map, int count)
return (struct ext3_dir_entry_2 *) (to - rec_len);
}
+/*
+ * Compact each dir entry in the range to the minimal rec_len.
+ * Returns pointer to last entry in range.
+ */
static struct ext3_dir_entry_2* dx_pack_dirents(char *base, int size)
{
struct ext3_dir_entry_2 *next, *to, *prev, *de = (struct ext3_dir_entry_2 *) base;
@@ -1131,6 +1172,11 @@ static struct ext3_dir_entry_2* dx_pack_dirents(char *base, int size)
return prev;
}
+/*
+ * Split a full leaf block to make room for a new dir entry.
+ * Allocate a new block, and move entries so that they are approx. equally full.
+ * Returns pointer to de in block into which the new entry will be inserted.
+ */
static struct ext3_dir_entry_2 *do_split(handle_t *handle, struct inode *dir,
struct buffer_head **bh,struct dx_frame *frame,
struct dx_hash_info *hinfo, int *error)
@@ -1142,7 +1188,7 @@ static struct ext3_dir_entry_2 *do_split(handle_t *handle, struct inode *dir,
u32 hash2;
struct dx_map_entry *map;
char *data1 = (*bh)->b_data, *data2;
- unsigned split;
+ unsigned split, move, size, i;
struct ext3_dir_entry_2 *de = NULL, *de2;
int err = 0;
@@ -1170,8 +1216,19 @@ static struct ext3_dir_entry_2 *do_split(handle_t *handle, struct inode *dir,
count = dx_make_map ((struct ext3_dir_entry_2 *) data1,
blocksize, hinfo, map);
map -= count;
- split = count/2; // need to adjust to actual middle
dx_sort_map (map, count);
+ /* Split the existing block in the middle, size-wise */
+ size = 0;
+ move = 0;
+ for (i = count-1; i >= 0; i--) {
+ /* is more than half of this entry in 2nd half of the block? */
+ if (size + map[i].size/2 > blocksize/2)
+ break;
+ size += map[i].size;
+ move++;
+ }
+ /* map index at which we will split */
+ split = count - move;
hash2 = map[split].hash;
continued = hash2 == map[split - 1].hash;
dxtrace(printk("Split block %i at %x, %i/%i\n",
diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c
index da224974af7..5fdb862e71c 100644
--- a/fs/ext4/namei.c
+++ b/fs/ext4/namei.c
@@ -140,7 +140,8 @@ struct dx_frame
struct dx_map_entry
{
u32 hash;
- u32 offs;
+ u16 offs;
+ u16 size;
};
#ifdef CONFIG_EXT4_INDEX
@@ -379,13 +380,28 @@ dx_probe(struct dentry *dentry, struct inode *dir,
entries = (struct dx_entry *) (((char *)&root->info) +
root->info.info_length);
- assert(dx_get_limit(entries) == dx_root_limit(dir,
- root->info.info_length));
+
+ if (dx_get_limit(entries) != dx_root_limit(dir,
+ root->info.info_length)) {
+ ext4_warning(dir->i_sb, __FUNCTION__,
+ "dx entry: limit != root limit");
+ brelse(bh);
+ *err = ERR_BAD_DX_DIR;
+ goto fail;
+ }
+
dxtrace (printk("Look up %x", hash));
while (1)
{
count = dx_get_count(entries);
- assert (count && count <= dx_get_limit(entries));
+ if (!count || count > dx_get_limit(entries)) {
+ ext4_warning(dir->i_sb, __FUNCTION__,
+ "dx entry: no count or count > limit");
+ brelse(bh);
+ *err = ERR_BAD_DX_DIR;
+ goto fail2;
+ }
+
p = entries + 1;
q = entries + count - 1;
while (p <= q)
@@ -423,8 +439,15 @@ dx_probe(struct dentry *dentry, struct inode *dir,
if (!(bh = ext4_bread (NULL,dir, dx_get_block(at), 0, err)))
goto fail2;
at = entries = ((struct dx_node *) bh->b_data)->entries;
- assert (dx_get_limit(entries) == dx_node_limit (dir));
+ if (dx_get_limit(entries) != dx_node_limit (dir)) {
+ ext4_warning(dir->i_sb, __FUNCTION__,
+ "dx entry: limit != node limit");
+ brelse(bh);
+ *err = ERR_BAD_DX_DIR;
+ goto fail2;
+ }
frame++;
+ frame->bh = NULL;
}
fail2:
while (frame >= frame_in) {
@@ -432,6 +455,10 @@ fail2:
frame--;
}
fail:
+ if (*err == ERR_BAD_DX_DIR)
+ ext4_warning(dir->i_sb, __FUNCTION__,
+ "Corrupt dir inode %ld, running e2fsck is "
+ "recommended.", dir->i_ino);
return NULL;
}
@@ -671,6 +698,10 @@ errout:
* Directory block splitting, compacting
*/
+/*
+ * Create map of hash values, offsets, and sizes, stored at end of block.
+ * Returns number of entries mapped.
+ */
static int dx_make_map (struct ext4_dir_entry_2 *de, int size,
struct dx_hash_info *hinfo, struct dx_map_entry *map_tail)
{
@@ -684,7 +715,8 @@ static int dx_make_map (struct ext4_dir_entry_2 *de, int size,
ext4fs_dirhash(de->name, de->name_len, &h);
map_tail--;
map_tail->hash = h.hash;
- map_tail->offs = (u32) ((char *) de - base);
+ map_tail->offs = (u16) ((char *) de - base);
+ map_tail->size = le16_to_cpu(de->rec_len);
count++;
cond_resched();
}
@@ -694,6 +726,7 @@ static int dx_make_map (struct ext4_dir_entry_2 *de, int size,
return count;
}
+/* Sort map by hash value */
static void dx_sort_map (struct dx_map_entry *map, unsigned count)
{
struct dx_map_entry *p, *q, *top = map + count - 1;
@@ -1089,6 +1122,10 @@ static inline void ext4_set_de_type(struct super_block *sb,
}
#ifdef CONFIG_EXT4_INDEX
+/*
+ * Move count entries from end of map between two memory locations.
+ * Returns pointer to last entry moved.
+ */
static struct ext4_dir_entry_2 *
dx_move_dirents(char *from, char *to, struct dx_map_entry *map, int count)
{
@@ -1107,6 +1144,10 @@ dx_move_dirents(char *from, char *to, struct dx_map_entry *map, int count)
return (struct ext4_dir_entry_2 *) (to - rec_len);
}
+/*
+ * Compact each dir entry in the range to the minimal rec_len.
+ * Returns pointer to last entry in range.
+ */
static struct ext4_dir_entry_2* dx_pack_dirents(char *base, int size)
{
struct ext4_dir_entry_2 *next, *to, *prev, *de = (struct ext4_dir_entry_2 *) base;
@@ -1129,6 +1170,11 @@ static struct ext4_dir_entry_2* dx_pack_dirents(char *base, int size)
return prev;
}
+/*
+ * Split a full leaf block to make room for a new dir entry.
+ * Allocate a new block, and move entries so that they are approx. equally full.
+ * Returns pointer to de in block into which the new entry will be inserted.
+ */
static struct ext4_dir_entry_2 *do_split(handle_t *handle, struct inode *dir,
struct buffer_head **bh,struct dx_frame *frame,
struct dx_hash_info *hinfo, int *error)
@@ -1140,7 +1186,7 @@ static struct ext4_dir_entry_2 *do_split(handle_t *handle, struct inode *dir,
u32 hash2;
struct dx_map_entry *map;
char *data1 = (*bh)->b_data, *data2;
- unsigned split;
+ unsigned split, move, size, i;
struct ext4_dir_entry_2 *de = NULL, *de2;
int err = 0;
@@ -1168,8 +1214,19 @@ static struct ext4_dir_entry_2 *do_split(handle_t *handle, struct inode *dir,
count = dx_make_map ((struct ext4_dir_entry_2 *) data1,
blocksize, hinfo, map);
map -= count;
- split = count/2; // need to adjust to actual middle
dx_sort_map (map, count);
+ /* Split the existing block in the middle, size-wise */
+ size = 0;
+ move = 0;
+ for (i = count-1; i >= 0; i--) {
+ /* is more than half of this entry in 2nd half of the block? */
+ if (size + map[i].size/2 > blocksize/2)
+ break;
+ size += map[i].size;
+ move++;
+ }
+ /* map index at which we will split */
+ split = count - move;
hash2 = map[split].hash;
continued = hash2 == map[split - 1].hash;
dxtrace(printk("Split block %i at %x, %i/%i\n",
diff --git a/fs/nfs/super.c b/fs/nfs/super.c
index 8ed593766f1..b878528b64c 100644
--- a/fs/nfs/super.c
+++ b/fs/nfs/super.c
@@ -345,8 +345,8 @@ void __exit unregister_nfs_fs(void)
unregister_shrinker(&acl_shrinker);
#ifdef CONFIG_NFS_V4
unregister_filesystem(&nfs4_fs_type);
- nfs_unregister_sysctl();
#endif
+ nfs_unregister_sysctl();
unregister_filesystem(&nfs_fs_type);
}
diff --git a/fs/xfs/linux-2.6/xfs_aops.c b/fs/xfs/linux-2.6/xfs_aops.c
index d9c40fe6419..5f152f60d74 100644
--- a/fs/xfs/linux-2.6/xfs_aops.c
+++ b/fs/xfs/linux-2.6/xfs_aops.c
@@ -181,6 +181,7 @@ xfs_setfilesize(
ip->i_d.di_size = isize;
ip->i_update_core = 1;
ip->i_update_size = 1;
+ mark_inode_dirty_sync(vn_to_inode(ioend->io_vnode));
}
xfs_iunlock(ip, XFS_ILOCK_EXCL);
diff --git a/fs/xfs/linux-2.6/xfs_super.c b/fs/xfs/linux-2.6/xfs_super.c
index 4528f9a3f30..491d1f4f202 100644
--- a/fs/xfs/linux-2.6/xfs_super.c
+++ b/fs/xfs/linux-2.6/xfs_super.c
@@ -415,8 +415,10 @@ xfs_fs_write_inode(
if (vp) {
vn_trace_entry(vp, __FUNCTION__, (inst_t *)__return_address);
- if (sync)
+ if (sync) {
+ filemap_fdatawait(inode->i_mapping);
flags |= FLUSH_SYNC;
+ }
error = bhv_vop_iflush(vp, flags);
if (error == EAGAIN)
error = sync? bhv_vop_iflush(vp, flags | FLUSH_LOG) : 0;
diff --git a/fs/xfs/xfs_buf_item.h b/fs/xfs/xfs_buf_item.h
index d7e13614306..fa25b7dcc6c 100644
--- a/fs/xfs/xfs_buf_item.h
+++ b/fs/xfs/xfs_buf_item.h
@@ -52,6 +52,11 @@ typedef struct xfs_buf_log_format_t {
#define XFS_BLI_UDQUOT_BUF 0x4
#define XFS_BLI_PDQUOT_BUF 0x8
#define XFS_BLI_GDQUOT_BUF 0x10
+/*
+ * This flag indicates that the buffer contains newly allocated
+ * inodes.
+ */
+#define XFS_BLI_INODE_NEW_BUF 0x20
#define XFS_BLI_CHUNK 128
#define XFS_BLI_SHIFT 7
diff --git a/fs/xfs/xfs_filestream.c b/fs/xfs/xfs_filestream.c
index ce2278611bb..16f8e175167 100644
--- a/fs/xfs/xfs_filestream.c
+++ b/fs/xfs/xfs_filestream.c
@@ -467,8 +467,7 @@ void
xfs_filestream_flush(
xfs_mount_t *mp)
{
- /* point in time flush, so keep the reaper running */
- xfs_mru_cache_flush(mp->m_filestream, 1);
+ xfs_mru_cache_flush(mp->m_filestream);
}
/*
diff --git a/fs/xfs/xfs_log_recover.c b/fs/xfs/xfs_log_recover.c
index 8ae6e8e5f3d..dacb19739cc 100644
--- a/fs/xfs/xfs_log_recover.c
+++ b/fs/xfs/xfs_log_recover.c
@@ -1874,6 +1874,7 @@ xlog_recover_do_inode_buffer(
/*ARGSUSED*/
STATIC void
xlog_recover_do_reg_buffer(
+ xfs_mount_t *mp,
xlog_recover_item_t *item,
xfs_buf_t *bp,
xfs_buf_log_format_t *buf_f)
@@ -1884,6 +1885,50 @@ xlog_recover_do_reg_buffer(
unsigned int *data_map = NULL;
unsigned int map_size = 0;
int error;
+ int stale_buf = 1;
+
+ /*
+ * Scan through the on-disk inode buffer and attempt to
+ * determine if it has been written to since it was logged.
+ *
+ * - If any of the magic numbers are incorrect then the buffer is stale
+ * - If any of the modes are non-zero then the buffer is not stale
+ * - If all of the modes are zero and at least one of the generation
+ * counts is non-zero then the buffer is stale
+ *
+ * If the end result is a stale buffer then the log buffer is replayed
+ * otherwise it is skipped.
+ *
+ * This heuristic is not perfect. It can be improved by scanning the
+ * entire inode chunk for evidence that any of the inode clusters have
+ * been updated. To fix this problem completely we will need a major
+ * architectural change to the logging system.
+ */
+ if (buf_f->blf_flags & XFS_BLI_INODE_NEW_BUF) {
+ xfs_dinode_t *dip;
+ int inodes_per_buf;
+ int mode_count = 0;
+ int gen_count = 0;
+
+ stale_buf = 0;
+ inodes_per_buf = XFS_BUF_COUNT(bp) >> mp->m_sb.sb_inodelog;
+ for (i = 0; i < inodes_per_buf; i++) {
+ dip = (xfs_dinode_t *)xfs_buf_offset(bp,
+ i * mp->m_sb.sb_inodesize);
+ if (be16_to_cpu(dip->di_core.di_magic) !=
+ XFS_DINODE_MAGIC) {
+ stale_buf = 1;
+ break;
+ }
+ if (be16_to_cpu(dip->di_core.di_mode))
+ mode_count++;
+ if (be16_to_cpu(dip->di_core.di_gen))
+ gen_count++;
+ }
+
+ if (!mode_count && gen_count)
+ stale_buf = 1;
+ }
switch (buf_f->blf_type) {
case XFS_LI_BUF:
@@ -1917,7 +1962,7 @@ xlog_recover_do_reg_buffer(
-1, 0, XFS_QMOPT_DOWARN,
"dquot_buf_recover");
}
- if (!error)
+ if (!error && stale_buf)
memcpy(xfs_buf_offset(bp,
(uint)bit << XFS_BLI_SHIFT), /* dest */
item->ri_buf[i].i_addr, /* source */
@@ -2089,7 +2134,7 @@ xlog_recover_do_dquot_buffer(
if (log->l_quotaoffs_flag & type)
return;
- xlog_recover_do_reg_buffer(item, bp, buf_f);
+ xlog_recover_do_reg_buffer(mp, item, bp, buf_f);
}
/*
@@ -2190,7 +2235,7 @@ xlog_recover_do_buffer_trans(
(XFS_BLI_UDQUOT_BUF|XFS_BLI_PDQUOT_BUF|XFS_BLI_GDQUOT_BUF)) {
xlog_recover_do_dquot_buffer(mp, log, item, bp, buf_f);
} else {
- xlog_recover_do_reg_buffer(item, bp, buf_f);
+ xlog_recover_do_reg_buffer(mp, item, bp, buf_f);
}
if (error)
return XFS_ERROR(error);
diff --git a/fs/xfs/xfs_mru_cache.c b/fs/xfs/xfs_mru_cache.c
index 7deb9e3cbbd..e0b358c1c53 100644
--- a/fs/xfs/xfs_mru_cache.c
+++ b/fs/xfs/xfs_mru_cache.c
@@ -206,8 +206,11 @@ _xfs_mru_cache_list_insert(
*/
if (!_xfs_mru_cache_migrate(mru, now)) {
mru->time_zero = now;
- if (!mru->next_reap)
- mru->next_reap = mru->grp_count * mru->grp_time;
+ if (!mru->queued) {
+ mru->queued = 1;
+ queue_delayed_work(xfs_mru_reap_wq, &mru->work,
+ mru->grp_count * mru->grp_time);
+ }
} else {
grp = (now - mru->time_zero) / mru->grp_time;
grp = (mru->lru_grp + grp) % mru->grp_count;
@@ -271,29 +274,26 @@ _xfs_mru_cache_reap(
struct work_struct *work)
{
xfs_mru_cache_t *mru = container_of(work, xfs_mru_cache_t, work.work);
- unsigned long now;
+ unsigned long now, next;
ASSERT(mru && mru->lists);
if (!mru || !mru->lists)
return;
mutex_spinlock(&mru->lock);
- now = jiffies;
- if (mru->reap_all ||
- (mru->next_reap && time_after(now, mru->next_reap))) {
- if (mru->reap_all)
- now += mru->grp_count * mru->grp_time * 2;
- mru->next_reap = _xfs_mru_cache_migrate(mru, now);
- _xfs_mru_cache_clear_reap_list(mru);
+ next = _xfs_mru_cache_migrate(mru, jiffies);
+ _xfs_mru_cache_clear_reap_list(mru);
+
+ mru->queued = next;
+ if ((mru->queued > 0)) {
+ now = jiffies;
+ if (next <= now)
+ next = 0;
+ else
+ next -= now;
+ queue_delayed_work(xfs_mru_reap_wq, &mru->work, next);
}
- /*
- * the process that triggered the reap_all is responsible
- * for restating the periodic reap if it is required.
- */
- if (!mru->reap_all)
- queue_delayed_work(xfs_mru_reap_wq, &mru->work, mru->grp_time);
- mru->reap_all = 0;
mutex_spinunlock(&mru->lock, 0);
}
@@ -352,7 +352,7 @@ xfs_mru_cache_create(
/* An extra list is needed to avoid reaping up to a grp_time early. */
mru->grp_count = grp_count + 1;
- mru->lists = kmem_alloc(mru->grp_count * sizeof(*mru->lists), KM_SLEEP);
+ mru->lists = kmem_zalloc(mru->grp_count * sizeof(*mru->lists), KM_SLEEP);
if (!mru->lists) {
err = ENOMEM;
@@ -374,11 +374,6 @@ xfs_mru_cache_create(
mru->grp_time = grp_time;
mru->free_func = free_func;
- /* start up the reaper event */
- mru->next_reap = 0;
- mru->reap_all = 0;
- queue_delayed_work(xfs_mru_reap_wq, &mru->work, mru->grp_time);
-
*mrup = mru;
exit:
@@ -394,35 +389,25 @@ exit:
* Call xfs_mru_cache_flush() to flush out all cached entries, calling their
* free functions as they're deleted. When this function returns, the caller is
* guaranteed that all the free functions for all the elements have finished
- * executing.
- *
- * While we are flushing, we stop the periodic reaper event from triggering.
- * Normally, we want to restart this periodic event, but if we are shutting
- * down the cache we do not want it restarted. hence the restart parameter
- * where 0 = do not restart reaper and 1 = restart reaper.
+ * executing and the reaper is not running.
*/
void
xfs_mru_cache_flush(
- xfs_mru_cache_t *mru,
- int restart)
+ xfs_mru_cache_t *mru)
{
if (!mru || !mru->lists)
return;
- cancel_rearming_delayed_workqueue(xfs_mru_reap_wq, &mru->work);
-
mutex_spinlock(&mru->lock);
- mru->reap_all = 1;
- mutex_spinunlock(&mru->lock, 0);
+ if (mru->queued) {
+ mutex_spinunlock(&mru->lock, 0);
+ cancel_rearming_delayed_workqueue(xfs_mru_reap_wq, &mru->work);
+ mutex_spinlock(&mru->lock);
+ }
- queue_work(xfs_mru_reap_wq, &mru->work.work);
- flush_workqueue(xfs_mru_reap_wq);
+ _xfs_mru_cache_migrate(mru, jiffies + mru->grp_count * mru->grp_time);
+ _xfs_mru_cache_clear_reap_list(mru);
- mutex_spinlock(&mru->lock);
- WARN_ON_ONCE(mru->reap_all != 0);
- mru->reap_all = 0;
- if (restart)
- queue_delayed_work(xfs_mru_reap_wq, &mru->work, mru->grp_time);
mutex_spinunlock(&mru->lock, 0);
}
@@ -433,8 +418,7 @@ xfs_mru_cache_destroy(
if (!mru || !mru->lists)
return;
- /* we don't want the reaper to restart here */
- xfs_mru_cache_flush(mru, 0);
+ xfs_mru_cache_flush(mru);
kmem_free(mru->lists, mru->grp_count * sizeof(*mru->lists));
kmem_free(mru, sizeof(*mru));
diff --git a/fs/xfs/xfs_mru_cache.h b/fs/xfs/xfs_mru_cache.h
index 624fd10ee8e..dd58ea1bbeb 100644
--- a/fs/xfs/xfs_mru_cache.h
+++ b/fs/xfs/xfs_mru_cache.h
@@ -32,11 +32,9 @@ typedef struct xfs_mru_cache
unsigned int grp_time; /* Time period spanned by grps. */
unsigned int lru_grp; /* Group containing time zero. */
unsigned long time_zero; /* Time first element was added. */
- unsigned long next_reap; /* Time that the reaper should
- next do something. */
- unsigned int reap_all; /* if set, reap all lists */
xfs_mru_cache_free_func_t free_func; /* Function pointer for freeing. */
struct delayed_work work; /* Workqueue data for reaping. */
+ unsigned int queued; /* work has been queued */
} xfs_mru_cache_t;
int xfs_mru_cache_init(void);
@@ -44,7 +42,7 @@ void xfs_mru_cache_uninit(void);
int xfs_mru_cache_create(struct xfs_mru_cache **mrup, unsigned int lifetime_ms,
unsigned int grp_count,
xfs_mru_cache_free_func_t free_func);
-void xfs_mru_cache_flush(xfs_mru_cache_t *mru, int restart);
+void xfs_mru_cache_flush(xfs_mru_cache_t *mru);
void xfs_mru_cache_destroy(struct xfs_mru_cache *mru);
int xfs_mru_cache_insert(struct xfs_mru_cache *mru, unsigned long key,
void *value);
diff --git a/fs/xfs/xfs_trans_buf.c b/fs/xfs/xfs_trans_buf.c
index 60b6b898022..95fff6872a2 100644
--- a/fs/xfs/xfs_trans_buf.c
+++ b/fs/xfs/xfs_trans_buf.c
@@ -966,6 +966,7 @@ xfs_trans_inode_alloc_buf(
ASSERT(atomic_read(&bip->bli_refcount) > 0);
bip->bli_flags |= XFS_BLI_INODE_ALLOC_BUF;
+ bip->bli_format.blf_flags |= XFS_BLI_INODE_NEW_BUF;
}
diff --git a/fs/xfs/xfs_vnodeops.c b/fs/xfs/xfs_vnodeops.c
index 1a5ad8cd97b..60345922990 100644
--- a/fs/xfs/xfs_vnodeops.c
+++ b/fs/xfs/xfs_vnodeops.c
@@ -1082,6 +1082,9 @@ xfs_fsync(
if (XFS_FORCED_SHUTDOWN(ip->i_mount))
return XFS_ERROR(EIO);
+ if (flag & FSYNC_DATA)
+ filemap_fdatawait(vn_to_inode(XFS_ITOV(ip))->i_mapping);
+
/*
* We always need to make sure that the required inode state
* is safe on disk. The vnode might be clean but because
@@ -3769,12 +3772,16 @@ xfs_inode_flush(
sync_lsn = log->l_last_sync_lsn;
GRANT_UNLOCK(log, s);
- if ((XFS_LSN_CMP(iip->ili_last_lsn, sync_lsn) <= 0))
- return 0;
+ if ((XFS_LSN_CMP(iip->ili_last_lsn, sync_lsn) > 0)) {
+ if (flags & FLUSH_SYNC)
+ log_flags |= XFS_LOG_SYNC;
+ error = xfs_log_force(mp, iip->ili_last_lsn, log_flags);
+ if (error)
+ return error;
+ }
- if (flags & FLUSH_SYNC)
- log_flags |= XFS_LOG_SYNC;
- return xfs_log_force(mp, iip->ili_last_lsn, log_flags);
+ if (ip->i_update_core == 0)
+ return 0;
}
}
@@ -3788,9 +3795,6 @@ xfs_inode_flush(
if (flags & FLUSH_INODE) {
int flush_flags;
- if (xfs_ipincount(ip))
- return EAGAIN;
-
if (flags & FLUSH_SYNC) {
xfs_ilock(ip, XFS_ILOCK_SHARED);
xfs_iflock(ip);
diff --git a/include/asm-blackfin/mach-bf561/cdefBF561.h b/include/asm-blackfin/mach-bf561/cdefBF561.h
index 6e87ab269ff..73d4d65249c 100644
--- a/include/asm-blackfin/mach-bf561/cdefBF561.h
+++ b/include/asm-blackfin/mach-bf561/cdefBF561.h
@@ -83,9 +83,9 @@ static __inline__ void bfin_write_VR_CTL(unsigned int val)
/* For MMR's that are reserved on Core B, set up defines to better integrate with other ports */
#define bfin_read_SWRST() bfin_read_SICA_SWRST()
-#define bfin_write_SWRST() bfin_write_SICA_SWRST()
+#define bfin_write_SWRST(val) bfin_write_SICA_SWRST(val)
#define bfin_read_SYSCR() bfin_read_SICA_SYSCR()
-#define bfin_write_SYSCR() bfin_write_SICA_SYSCR()
+#define bfin_write_SYSCR(val) bfin_write_SICA_SYSCR(val)
/* System Reset and Interrupt Controller registers for core A (0xFFC0 0100-0xFFC0 01FF) */
#define bfin_read_SICA_SWRST() bfin_read16(SICA_SWRST)
diff --git a/include/asm-blackfin/string.h b/include/asm-blackfin/string.h
index 6f1eb7d6d3c..e8ada91ab00 100644
--- a/include/asm-blackfin/string.h
+++ b/include/asm-blackfin/string.h
@@ -9,13 +9,16 @@ extern inline char *strcpy(char *dest, const char *src)
char *xdest = dest;
char temp = 0;
- __asm__ __volatile__
- ("1:\t%2 = B [%1++] (Z);\n\t"
- "B [%0++] = %2;\n\t"
- "CC = %2;\n\t"
- "if cc jump 1b (bp);\n"
- : "+&a" (dest), "+&a" (src), "=&d" (temp)
- ::"memory", "CC");
+ __asm__ __volatile__ (
+ "1:"
+ "%2 = B [%1++] (Z);"
+ "B [%0++] = %2;"
+ "CC = %2;"
+ "if cc jump 1b (bp);"
+ : "+&a" (dest), "+&a" (src), "=&d" (temp)
+ :
+ : "memory", "CC");
+
return xdest;
}
@@ -28,37 +31,56 @@ extern inline char *strncpy(char *dest, const char *src, size_t n)
if (n == 0)
return xdest;
- __asm__ __volatile__
- ("1:\t%3 = B [%1++] (Z);\n\t"
- "B [%0++] = %3;\n\t"
- "CC = %3;\n\t"
- "if ! cc jump 2f;\n\t"
- "%2 += -1;\n\t"
- "CC = %2 == 0;\n\t"
- "if ! cc jump 1b (bp);\n"
- "2:\n"
- : "+&a" (dest), "+&a" (src), "+&da" (n), "=&d" (temp)
- ::"memory", "CC");
+ __asm__ __volatile__ (
+ "1:"
+ "%3 = B [%1++] (Z);"
+ "B [%0++] = %3;"
+ "CC = %3;"
+ "if ! cc jump 2f;"
+ "%2 += -1;"
+ "CC = %2 == 0;"
+ "if ! cc jump 1b (bp);"
+ "jump 4f;"
+ "2:"
+ /* if src is shorter than n, we need to null pad bytes now */
+ "%3 = 0;"
+ "3:"
+ "%2 += -1;"
+ "CC = %2 == 0;"
+ "if cc jump 4f;"
+ "B [%0++] = %3;"
+ "jump 3b;"
+ "4:"
+ : "+&a" (dest), "+&a" (src), "+&da" (n), "=&d" (temp)
+ :
+ : "memory", "CC");
+
return xdest;
}
#define __HAVE_ARCH_STRCMP
extern inline int strcmp(const char *cs, const char *ct)
{
- char __res1, __res2;
-
- __asm__
- ("1:\t%2 = B[%0++] (Z);\n\t" /* get *cs */
- "%3 = B[%1++] (Z);\n\t" /* get *ct */
- "CC = %2 == %3;\n\t" /* compare a byte */
- "if ! cc jump 2f;\n\t" /* not equal, break out */
- "CC = %2;\n\t" /* at end of cs? */
- "if cc jump 1b (bp);\n\t" /* no, keep going */
- "jump.s 3f;\n" /* strings are equal */
- "2:\t%2 = %2 - %3;\n" /* *cs - *ct */
- "3:\n"
- : "+&a" (cs), "+&a" (ct), "=&d" (__res1), "=&d" (__res2)
- : : "CC");
+ /* need to use int's here so the char's in the assembly don't get
+ * sign extended incorrectly when we don't want them to be
+ */
+ int __res1, __res2;
+
+ __asm__ __volatile__ (
+ "1:"
+ "%2 = B[%0++] (Z);" /* get *cs */
+ "%3 = B[%1++] (Z);" /* get *ct */
+ "CC = %2 == %3;" /* compare a byte */
+ "if ! cc jump 2f;" /* not equal, break out */
+ "CC = %2;" /* at end of cs? */
+ "if cc jump 1b (bp);" /* no, keep going */
+ "jump.s 3f;" /* strings are equal */
+ "2:"
+ "%2 = %2 - %3;" /* *cs - *ct */
+ "3:"
+ : "+&a" (cs), "+&a" (ct), "=&d" (__res1), "=&d" (__res2)
+ :
+ : "memory", "CC");
return __res1;
}
@@ -66,26 +88,35 @@ extern inline int strcmp(const char *cs, const char *ct)
#define __HAVE_ARCH_STRNCMP
extern inline int strncmp(const char *cs, const char *ct, size_t count)
{
- char __res1, __res2;
+ /* need to use int's here so the char's in the assembly don't get
+ * sign extended incorrectly when we don't want them to be
+ */
+ int __res1, __res2;
if (!count)
return 0;
- __asm__
- ("1:\t%3 = B[%0++] (Z);\n\t" /* get *cs */
- "%4 = B[%1++] (Z);\n\t" /* get *ct */
- "CC = %3 == %4;\n\t" /* compare a byte */
- "if ! cc jump 3f;\n\t" /* not equal, break out */
- "CC = %3;\n\t" /* at end of cs? */
- "if ! cc jump 4f;\n\t" /* yes, all done */
- "%2 += -1;\n\t" /* no, adjust count */
- "CC = %2 == 0;\n\t"
- "if ! cc jump 1b;\n" /* more to do, keep going */
- "2:\t%3 = 0;\n\t" /* strings are equal */
- "jump.s 4f;\n"
- "3:\t%3 = %3 - %4;\n" /* *cs - *ct */
- "4:"
- : "+&a" (cs), "+&a" (ct), "+&da" (count), "=&d" (__res1), "=&d" (__res2)
- : : "CC");
+
+ __asm__ __volatile__ (
+ "1:"
+ "%3 = B[%0++] (Z);" /* get *cs */
+ "%4 = B[%1++] (Z);" /* get *ct */
+ "CC = %3 == %4;" /* compare a byte */
+ "if ! cc jump 3f;" /* not equal, break out */
+ "CC = %3;" /* at end of cs? */
+ "if ! cc jump 4f;" /* yes, all done */
+ "%2 += -1;" /* no, adjust count */
+ "CC = %2 == 0;"
+ "if ! cc jump 1b;" /* more to do, keep going */
+ "2:"
+ "%3 = 0;" /* strings are equal */
+ "jump.s 4f;"
+ "3:"
+ "%3 = %3 - %4;" /* *cs - *ct */
+ "4:"
+ : "+&a" (cs), "+&a" (ct), "+&da" (count), "=&d" (__res1), "=&d" (__res2)
+ :
+ : "memory", "CC");
+
return __res1;
}
diff --git a/include/asm-mips/compiler.h b/include/asm-mips/compiler.h
index 169ae26105e..aa6b876bbd7 100644
--- a/include/asm-mips/compiler.h
+++ b/include/asm-mips/compiler.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2004 Maciej W. Rozycki
+ * Copyright (C) 2004, 2007 Maciej W. Rozycki
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
@@ -9,8 +9,10 @@
#define _ASM_COMPILER_H
#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)
+#define GCC_IMM_ASM "n"
#define GCC_REG_ACCUM "$0"
#else
+#define GCC_IMM_ASM "rn"
#define GCC_REG_ACCUM "accum"
#endif
diff --git a/include/asm-mips/mach-generic/ide.h b/include/asm-mips/mach-generic/ide.h
index 2b928577be5..a77128362a7 100644
--- a/include/asm-mips/mach-generic/ide.h
+++ b/include/asm-mips/mach-generic/ide.h
@@ -29,6 +29,35 @@
#define IDE_ARCH_OBSOLETE_DEFAULTS
+static __inline__ int ide_probe_legacy(void)
+{
+#ifdef CONFIG_PCI
+ struct pci_dev *dev;
+ /*
+ * This can be called on the ide_setup() path, super-early in
+ * boot. But the down_read() will enable local interrupts,
+ * which can cause some machines to crash. So here we detect
+ * and flag that situation and bail out early.
+ */
+ if (no_pci_devices())
+ return 0;
+ dev = pci_get_class(PCI_CLASS_BRIDGE_EISA << 8, NULL);
+ if (dev)
+ goto found;
+ dev = pci_get_class(PCI_CLASS_BRIDGE_ISA << 8, NULL);
+ if (dev)
+ goto found;
+ return 0;
+found:
+ pci_dev_put(dev);
+ return 1;
+#elif defined(CONFIG_EISA) || defined(CONFIG_ISA)
+ return 1;
+#else
+ return 0;
+#endif
+}
+
static __inline__ int ide_default_irq(unsigned long base)
{
switch (base) {
@@ -45,6 +74,8 @@ static __inline__ int ide_default_irq(unsigned long base)
static __inline__ unsigned long ide_default_io_base(int index)
{
+ if (!ide_probe_legacy())
+ return 0;
/*
* If PCI is present then it is not safe to poke around
* the other legacy IDE ports. Only 0x1f0 and 0x170 are
diff --git a/include/asm-powerpc/time.h b/include/asm-powerpc/time.h
index fdc271ebe41..fa331dad97c 100644
--- a/include/asm-powerpc/time.h
+++ b/include/asm-powerpc/time.h
@@ -149,6 +149,11 @@ static inline u64 get_tb(void)
}
#endif /* !CONFIG_PPC64 */
+static inline u64 get_tb_or_rtc(void)
+{
+ return __USE_RTC() ? get_rtc() : get_tb();
+}
+
static inline void set_tb(unsigned int upper, unsigned int lower)
{
mtspr(SPRN_TBWL, 0);
diff --git a/include/asm-sparc64/oplib.h b/include/asm-sparc64/oplib.h
index 86dc5c018a1..55c5bb27e4d 100644
--- a/include/asm-sparc64/oplib.h
+++ b/include/asm-sparc64/oplib.h
@@ -297,11 +297,7 @@ extern void prom_sun4v_guest_soft_state(void);
extern int prom_ihandle2path(int handle, char *buffer, int bufsize);
/* Client interface level routines. */
-extern void prom_set_trap_table(unsigned long tba);
-extern void prom_set_trap_table_sun4v(unsigned long tba, unsigned long mmfsa);
-
extern long p1275_cmd(const char *, long, ...);
-
#if 0
#define P1275_SIZE(x) ((((long)((x) / 32)) << 32) | (x))
diff --git a/include/asm-xtensa/bugs.h b/include/asm-xtensa/bugs.h
index c4228532013..69b29d19824 100644
--- a/include/asm-xtensa/bugs.h
+++ b/include/asm-xtensa/bugs.h
@@ -13,10 +13,6 @@
#ifndef _XTENSA_BUGS_H
#define _XTENSA_BUGS_H
-#include <asm/processor.h>
-
-static void __init check_bugs(void)
-{
-}
+static void check_bugs(void) { }
#endif /* _XTENSA_BUGS_H */
diff --git a/include/asm-xtensa/cache.h b/include/asm-xtensa/cache.h
index 1c4a78f29ae..3bba2a540cf 100644
--- a/include/asm-xtensa/cache.h
+++ b/include/asm-xtensa/cache.h
@@ -19,6 +19,15 @@
#define DCACHE_WAY_SIZE (XCHAL_DCACHE_SIZE/XCHAL_DCACHE_WAYS)
#define ICACHE_WAY_SIZE (XCHAL_ICACHE_SIZE/XCHAL_ICACHE_WAYS)
+#define DCACHE_WAY_SHIFT (XCHAL_DCACHE_SETWIDTH + XCHAL_DCACHE_LINEWIDTH)
+#define ICACHE_WAY_SHIFT (XCHAL_ICACHE_SETWIDTH + XCHAL_ICACHE_LINEWIDTH)
+
+/* Maximum cache size per way. */
+#if DCACHE_WAY_SIZE >= ICACHE_WAY_SIZE
+# define CACHE_WAY_SIZE DCACHE_WAY_SIZE
+#else
+# define CACHE_WAY_SIZE ICACHE_WAY_SIZE
+#endif
#endif /* _XTENSA_CACHE_H */
diff --git a/include/asm-xtensa/cacheflush.h b/include/asm-xtensa/cacheflush.h
index 22ef901b784..b773c57e75a 100644
--- a/include/asm-xtensa/cacheflush.h
+++ b/include/asm-xtensa/cacheflush.h
@@ -5,7 +5,7 @@
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
- * (C) 2001 - 2006 Tensilica Inc.
+ * (C) 2001 - 2007 Tensilica Inc.
*/
#ifndef _XTENSA_CACHEFLUSH_H
@@ -18,10 +18,7 @@
#include <asm/page.h>
/*
- * flush and invalidate data cache, invalidate instruction cache:
- *
- * __flush_invalidate_cache_all()
- * __flush_invalidate_cache_range(from,sze)
+ * Lo-level routines for cache flushing.
*
* invalidate data or instruction cache:
*
@@ -40,26 +37,39 @@
* __flush_invalidate_dcache_all()
* __flush_invalidate_dcache_page(adr)
* __flush_invalidate_dcache_range(from,size)
+ *
+ * specials for cache aliasing:
+ *
+ * __flush_invalidate_dcache_page_alias(vaddr,paddr)
+ * __invalidate_icache_page_alias(vaddr,paddr)
*/
-extern void __flush_invalidate_cache_all(void);
-extern void __flush_invalidate_cache_range(unsigned long, unsigned long);
-extern void __flush_invalidate_dcache_all(void);
+extern void __invalidate_dcache_all(void);
extern void __invalidate_icache_all(void);
-
extern void __invalidate_dcache_page(unsigned long);
extern void __invalidate_icache_page(unsigned long);
extern void __invalidate_icache_range(unsigned long, unsigned long);
extern void __invalidate_dcache_range(unsigned long, unsigned long);
+
#if XCHAL_DCACHE_IS_WRITEBACK
+extern void __flush_invalidate_dcache_all(void);
extern void __flush_dcache_page(unsigned long);
+extern void __flush_dcache_range(unsigned long, unsigned long);
extern void __flush_invalidate_dcache_page(unsigned long);
extern void __flush_invalidate_dcache_range(unsigned long, unsigned long);
#else
-# define __flush_dcache_page(p) do { } while(0)
-# define __flush_invalidate_dcache_page(p) do { } while(0)
-# define __flush_invalidate_dcache_range(p,s) do { } while(0)
+# define __flush_dcache_range(p,s) do { } while(0)
+# define __flush_dcache_page(p) do { } while(0)
+# define __flush_invalidate_dcache_page(p) __invalidate_dcache_page(p)
+# define __flush_invalidate_dcache_range(p,s) __invalidate_dcache_range(p,s)
+#endif
+
+#if (DCACHE_WAY_SIZE > PAGE_SIZE)
+extern void __flush_invalidate_dcache_page_alias(unsigned long, unsigned long);
+#endif
+#if (ICACHE_WAY_SIZE > PAGE_SIZE)
+extern void __invalidate_icache_page_alias(unsigned long, unsigned long);
#endif
/*
@@ -71,17 +81,21 @@ extern void __flush_invalidate_dcache_range(unsigned long, unsigned long);
* (see also Documentation/cachetlb.txt)
*/
-#if (DCACHE_WAY_SIZE > PAGE_SIZE) && XCHAL_DCACHE_IS_WRITEBACK
+#if (DCACHE_WAY_SIZE > PAGE_SIZE)
-#define flush_cache_all() __flush_invalidate_cache_all();
-#define flush_cache_mm(mm) __flush_invalidate_cache_all();
-#define flush_cache_dup_mm(mm) __flush_invalidate_cache_all();
+#define flush_cache_all() \
+ do { \
+ __flush_invalidate_dcache_all(); \
+ __invalidate_icache_all(); \
+ } while (0)
-#define flush_cache_vmap(start,end) __flush_invalidate_cache_all();
-#define flush_cache_vunmap(start,end) __flush_invalidate_cache_all();
+#define flush_cache_mm(mm) flush_cache_all()
+#define flush_cache_dup_mm(mm) flush_cache_mm(mm)
-extern void flush_dcache_page(struct page*);
+#define flush_cache_vmap(start,end) flush_cache_all()
+#define flush_cache_vunmap(start,end) flush_cache_all()
+extern void flush_dcache_page(struct page*);
extern void flush_cache_range(struct vm_area_struct*, ulong, ulong);
extern void flush_cache_page(struct vm_area_struct*, unsigned long, unsigned long);
@@ -101,24 +115,39 @@ extern void flush_cache_page(struct vm_area_struct*, unsigned long, unsigned lon
#endif
+/* Ensure consistency between data and instruction cache. */
#define flush_icache_range(start,end) \
- __invalidate_icache_range(start,(end)-(start))
+ do { \
+ __flush_dcache_range(start, (end) - (start)); \
+ __invalidate_icache_range(start,(end) - (start)); \
+ } while (0)
/* This is not required, see Documentation/cachetlb.txt */
-
-#define flush_icache_page(vma,page) do { } while(0)
+#define flush_icache_page(vma,page) do { } while (0)
#define flush_dcache_mmap_lock(mapping) do { } while (0)
#define flush_dcache_mmap_unlock(mapping) do { } while (0)
+#if (DCACHE_WAY_SIZE > PAGE_SIZE)
-#define copy_to_user_page(vma, page, vaddr, dst, src, len) \
- memcpy(dst, src, len)
+extern void copy_to_user_page(struct vm_area_struct*, struct page*,
+ unsigned long, void*, const void*, unsigned long);
+extern void copy_from_user_page(struct vm_area_struct*, struct page*,
+ unsigned long, void*, const void*, unsigned long);
+
+#else
+
+#define copy_to_user_page(vma, page, vaddr, dst, src, len) \
+ do { \
+ memcpy(dst, src, len); \
+ __flush_dcache_range((unsigned long) dst, len); \
+ __invalidate_icache_range((unsigned long) dst, len); \
+ } while (0)
#define copy_from_user_page(vma, page, vaddr, dst, src, len) \
memcpy(dst, src, len)
-#endif /* __KERNEL__ */
+#endif
+#endif /* __KERNEL__ */
#endif /* _XTENSA_CACHEFLUSH_H */
-
diff --git a/include/asm-xtensa/elf.h b/include/asm-xtensa/elf.h
index 1569b53cec9..7083d46766a 100644
--- a/include/asm-xtensa/elf.h
+++ b/include/asm-xtensa/elf.h
@@ -20,6 +20,56 @@
#define EM_XTENSA 94
#define EM_XTENSA_OLD 0xABC7
+/* Xtensa relocations defined by the ABIs */
+
+#define R_XTENSA_NONE 0
+#define R_XTENSA_32 1
+#define R_XTENSA_RTLD 2
+#define R_XTENSA_GLOB_DAT 3
+#define R_XTENSA_JMP_SLOT 4
+#define R_XTENSA_RELATIVE 5
+#define R_XTENSA_PLT 6
+#define R_XTENSA_OP0 8
+#define R_XTENSA_OP1 9
+#define R_XTENSA_OP2 10
+#define R_XTENSA_ASM_EXPAND 11
+#define R_XTENSA_ASM_SIMPLIFY 12
+#define R_XTENSA_GNU_VTINHERIT 15
+#define R_XTENSA_GNU_VTENTRY 16
+#define R_XTENSA_DIFF8 17
+#define R_XTENSA_DIFF16 18
+#define R_XTENSA_DIFF32 19
+#define R_XTENSA_SLOT0_OP 20
+#define R_XTENSA_SLOT1_OP 21
+#define R_XTENSA_SLOT2_OP 22
+#define R_XTENSA_SLOT3_OP 23
+#define R_XTENSA_SLOT4_OP 24
+#define R_XTENSA_SLOT5_OP 25
+#define R_XTENSA_SLOT6_OP 26
+#define R_XTENSA_SLOT7_OP 27
+#define R_XTENSA_SLOT8_OP 28
+#define R_XTENSA_SLOT9_OP 29
+#define R_XTENSA_SLOT10_OP 30
+#define R_XTENSA_SLOT11_OP 31
+#define R_XTENSA_SLOT12_OP 32
+#define R_XTENSA_SLOT13_OP 33
+#define R_XTENSA_SLOT14_OP 34
+#define R_XTENSA_SLOT0_ALT 35
+#define R_XTENSA_SLOT1_ALT 36
+#define R_XTENSA_SLOT2_ALT 37
+#define R_XTENSA_SLOT3_ALT 38
+#define R_XTENSA_SLOT4_ALT 39
+#define R_XTENSA_SLOT5_ALT 40
+#define R_XTENSA_SLOT6_ALT 41
+#define R_XTENSA_SLOT7_ALT 42
+#define R_XTENSA_SLOT8_ALT 43
+#define R_XTENSA_SLOT9_ALT 44
+#define R_XTENSA_SLOT10_ALT 45
+#define R_XTENSA_SLOT11_ALT 46
+#define R_XTENSA_SLOT12_ALT 47
+#define R_XTENSA_SLOT13_ALT 48
+#define R_XTENSA_SLOT14_ALT 49
+
/* ELF register definitions. This is needed for core dump support. */
/*
diff --git a/include/asm-xtensa/io.h b/include/asm-xtensa/io.h
index 0faa614d969..47c3616ea9a 100644
--- a/include/asm-xtensa/io.h
+++ b/include/asm-xtensa/io.h
@@ -14,6 +14,7 @@
#ifdef __KERNEL__
#include <asm/byteorder.h>
#include <asm/page.h>
+#include <linux/kernel.h>
#include <linux/types.h>
diff --git a/include/asm-xtensa/ioctls.h b/include/asm-xtensa/ioctls.h
index 39e6f23921b..0ffa942954b 100644
--- a/include/asm-xtensa/ioctls.h
+++ b/include/asm-xtensa/ioctls.h
@@ -91,6 +91,10 @@
#define TIOCSBRK _IO('T', 39) /* BSD compatibility */
#define TIOCCBRK _IO('T', 40) /* BSD compatibility */
#define TIOCGSID _IOR('T', 41, pid_t) /* Return the session ID of FD*/
+#define TCGETS2 _IOR('T', 42, struct termios2)
+#define TCSETS2 _IOW('T', 43, struct termios2)
+#define TCSETSW2 _IOW('T', 44, struct termios2)
+#define TCSETSF2 _IOW('T', 45, struct termios2)
#define TIOCGPTN _IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */
#define TIOCSPTLCK _IOW('T',0x31, int) /* Lock/unlock Pty */
diff --git a/include/asm-xtensa/page.h b/include/asm-xtensa/page.h
index 1213cde7543..55ce2c9749a 100644
--- a/include/asm-xtensa/page.h
+++ b/include/asm-xtensa/page.h
@@ -1,11 +1,11 @@
/*
- * linux/include/asm-xtensa/page.h
+ * include/asm-xtensa/page.h
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version2 as
* published by the Free Software Foundation.
*
- * Copyright (C) 2001 - 2005 Tensilica Inc.
+ * Copyright (C) 2001 - 2007 Tensilica Inc.
*/
#ifndef _XTENSA_PAGE_H
@@ -14,6 +14,12 @@
#ifdef __KERNEL__
#include <asm/processor.h>
+#include <asm/types.h>
+#include <asm/cache.h>
+
+/*
+ * Fixed TLB translations in the processor.
+ */
#define XCHAL_KSEG_CACHED_VADDR 0xd0000000
#define XCHAL_KSEG_BYPASS_VADDR 0xd8000000
@@ -26,13 +32,60 @@
*/
#define PAGE_SHIFT 12
-#define PAGE_SIZE (1 << PAGE_SHIFT)
+#define PAGE_SIZE (__XTENSA_UL_CONST(1) << PAGE_SHIFT)
#define PAGE_MASK (~(PAGE_SIZE-1))
#define PAGE_ALIGN(addr) (((addr)+PAGE_SIZE - 1) & PAGE_MASK)
#define PAGE_OFFSET XCHAL_KSEG_CACHED_VADDR
-#define MAX_MEM_PFN XCHAL_KSEG_SIZE
-#define PGTABLE_START 0x80000000
+#define MAX_MEM_PFN XCHAL_KSEG_SIZE
+#define PGTABLE_START 0x80000000
+
+/*
+ * Cache aliasing:
+ *
+ * If the cache size for one way is greater than the page size, we have to
+ * deal with cache aliasing. The cache index is wider than the page size:
+ *
+ * | |cache| cache index
+ * | pfn |off| virtual address
+ * |xxxx:X|zzz|
+ * | : | |
+ * | \ / | |
+ * |trans.| |
+ * | / \ | |
+ * |yyyy:Y|zzz| physical address
+ *
+ * When the page number is translated to the physical page address, the lowest
+ * bit(s) (X) that are part of the cache index are also translated (Y).
+ * If this translation changes bit(s) (X), the cache index is also afected,
+ * thus resulting in a different cache line than before.
+ * The kernel does not provide a mechanism to ensure that the page color
+ * (represented by this bit) remains the same when allocated or when pages
+ * are remapped. When user pages are mapped into kernel space, the color of
+ * the page might also change.
+ *
+ * We use the address space VMALLOC_END ... VMALLOC_END + DCACHE_WAY_SIZE * 2
+ * to temporarily map a patch so we can match the color.
+ */
+
+#if DCACHE_WAY_SIZE > PAGE_SIZE
+# define DCACHE_ALIAS_ORDER (DCACHE_WAY_SHIFT - PAGE_SHIFT)
+# define DCACHE_ALIAS_MASK (PAGE_MASK & (DCACHE_WAY_SIZE - 1))
+# define DCACHE_ALIAS(a) (((a) & DCACHE_ALIAS_MASK) >> PAGE_SHIFT)
+# define DCACHE_ALIAS_EQ(a,b) ((((a) ^ (b)) & DCACHE_ALIAS_MASK) == 0)
+#else
+# define DCACHE_ALIAS_ORDER 0
+#endif
+
+#if ICACHE_WAY_SIZE > PAGE_SIZE
+# define ICACHE_ALIAS_ORDER (ICACHE_WAY_SHIFT - PAGE_SHIFT)
+# define ICACHE_ALIAS_MASK (PAGE_MASK & (ICACHE_WAY_SIZE - 1))
+# define ICACHE_ALIAS(a) (((a) & ICACHE_ALIAS_MASK) >> PAGE_SHIFT)
+# define ICACHE_ALIAS_EQ(a,b) ((((a) ^ (b)) & ICACHE_ALIAS_MASK) == 0)
+#else
+# define ICACHE_ALIAS_ORDER 0
+#endif
+
#ifdef __ASSEMBLY__
@@ -58,34 +111,23 @@ typedef struct { unsigned long pgprot; } pgprot_t;
/*
* Pure 2^n version of get_order
+ * Use 'nsau' instructions if supported by the processor or the generic version.
*/
-static inline int get_order(unsigned long size)
+#if XCHAL_HAVE_NSA
+
+static inline __attribute_const__ int get_order(unsigned long size)
{
- int order;
-#ifndef XCHAL_HAVE_NSU
- unsigned long x1, x2, x4, x8, x16;
-
- size = (size + PAGE_SIZE - 1) >> PAGE_SHIFT;
- x1 = size & 0xAAAAAAAA;
- x2 = size & 0xCCCCCCCC;
- x4 = size & 0xF0F0F0F0;
- x8 = size & 0xFF00FF00;
- x16 = size & 0xFFFF0000;
- order = x2 ? 2 : 0;
- order += (x16 != 0) * 16;
- order += (x8 != 0) * 8;
- order += (x4 != 0) * 4;
- order += (x1 != 0);
-
- return order;
-#else
- size = (size - 1) >> PAGE_SHIFT;
- asm ("nsau %0, %1" : "=r" (order) : "r" (size));
- return 32 - order;
-#endif
+ int lz;
+ asm ("nsau %0, %1" : "=r" (lz) : "r" ((size - 1) >> PAGE_SHIFT));
+ return 32 - lz;
}
+#else
+
+# include <asm-generic/page.h>
+
+#endif
struct page;
extern void clear_page(void *page);
@@ -96,11 +138,11 @@ extern void copy_page(void *to, void *from);
* some extra work
*/
-#if (DCACHE_WAY_SIZE > PAGE_SIZE)
-void clear_user_page(void *addr, unsigned long vaddr, struct page* page);
-void copy_user_page(void *to,void* from,unsigned long vaddr,struct page* page);
+#if DCACHE_WAY_SIZE > PAGE_SIZE
+extern void clear_user_page(void*, unsigned long, struct page*);
+extern void copy_user_page(void*, void*, unsigned long, struct page*);
#else
-# define clear_user_page(page,vaddr,pg) clear_page(page)
+# define clear_user_page(page, vaddr, pg) clear_page(page)
# define copy_user_page(to, from, vaddr, pg) copy_page(to, from)
#endif
diff --git a/include/asm-xtensa/pgalloc.h b/include/asm-xtensa/pgalloc.h
index d56ddf2055e..3e5b5652510 100644
--- a/include/asm-xtensa/pgalloc.h
+++ b/include/asm-xtensa/pgalloc.h
@@ -1,11 +1,11 @@
/*
- * linux/include/asm-xtensa/pgalloc.h
+ * include/asm-xtensa/pgalloc.h
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
- * Copyright (C) 2001-2005 Tensilica Inc.
+ * Copyright (C) 2001-2007 Tensilica Inc.
*/
#ifndef _XTENSA_PGALLOC_H
@@ -13,103 +13,54 @@
#ifdef __KERNEL__
-#include <linux/threads.h>
#include <linux/highmem.h>
-#include <asm/processor.h>
-#include <asm/cacheflush.h>
-
-
-/* Cache aliasing:
- *
- * If the cache size for one way is greater than the page size, we have to
- * deal with cache aliasing. The cache index is wider than the page size:
- *
- * |cache |
- * |pgnum |page| virtual address
- * |xxxxxX|zzzz|
- * | | |
- * \ / | |
- * trans.| |
- * / \ | |
- * |yyyyyY|zzzz| physical address
- *
- * When the page number is translated to the physical page address, the lowest
- * bit(s) (X) that are also part of the cache index are also translated (Y).
- * If this translation changes this bit (X), the cache index is also afected,
- * thus resulting in a different cache line than before.
- * The kernel does not provide a mechanism to ensure that the page color
- * (represented by this bit) remains the same when allocated or when pages
- * are remapped. When user pages are mapped into kernel space, the color of
- * the page might also change.
- *
- * We use the address space VMALLOC_END ... VMALLOC_END + DCACHE_WAY_SIZE * 2
- * to temporarily map a patch so we can match the color.
- */
-
-#if (DCACHE_WAY_SIZE > PAGE_SIZE)
-# define PAGE_COLOR_MASK (PAGE_MASK & (DCACHE_WAY_SIZE-1))
-# define PAGE_COLOR(a) \
- (((unsigned long)(a)&PAGE_COLOR_MASK) >> PAGE_SHIFT)
-# define PAGE_COLOR_EQ(a,b) \
- ((((unsigned long)(a) ^ (unsigned long)(b)) & PAGE_COLOR_MASK) == 0)
-# define PAGE_COLOR_MAP0(v) \
- (VMALLOC_END + ((unsigned long)(v) & PAGE_COLOR_MASK))
-# define PAGE_COLOR_MAP1(v) \
- (VMALLOC_END + ((unsigned long)(v) & PAGE_COLOR_MASK) + DCACHE_WAY_SIZE)
-#endif
/*
* Allocating and freeing a pmd is trivial: the 1-entry pmd is
* inside the pgd, so has no extra memory associated with it.
*/
-#define pgd_free(pgd) free_page((unsigned long)(pgd))
-
-#if (DCACHE_WAY_SIZE > PAGE_SIZE) && XCHAL_DCACHE_IS_WRITEBACK
+#define pmd_populate_kernel(mm, pmdp, ptep) \
+ (pmd_val(*(pmdp)) = ((unsigned long)ptep))
+#define pmd_populate(mm, pmdp, page) \
+ (pmd_val(*(pmdp)) = ((unsigned long)page_to_virt(page)))
-static inline void
-pmd_populate_kernel(struct mm_struct *mm, pmd_t *pmdp, pte_t *pte)
+static inline pgd_t*
+pgd_alloc(struct mm_struct *mm)
{
- pmd_val(*(pmdp)) = (unsigned long)(pte);
- __asm__ __volatile__ ("memw; dhwb %0, 0; dsync" :: "a" (pmdp));
+ return (pgd_t*) __get_free_pages(GFP_KERNEL | __GFP_ZERO, PGD_ORDER);
}
-static inline void
-pmd_populate(struct mm_struct *mm, pmd_t *pmdp, struct page *page)
+static inline void pgd_free(pgd_t *pgd)
{
- pmd_val(*(pmdp)) = (unsigned long)page_to_virt(page);
- __asm__ __volatile__ ("memw; dhwb %0, 0; dsync" :: "a" (pmdp));
+ free_page((unsigned long)pgd);
}
+/* Use a slab cache for the pte pages (see also sparc64 implementation) */
+extern struct kmem_cache *pgtable_cache;
-#else
-
-# define pmd_populate_kernel(mm, pmdp, pte) \
- (pmd_val(*(pmdp)) = (unsigned long)(pte))
-# define pmd_populate(mm, pmdp, page) \
- (pmd_val(*(pmdp)) = (unsigned long)page_to_virt(page))
-
-#endif
-
-static inline pgd_t*
-pgd_alloc(struct mm_struct *mm)
+static inline pte_t *pte_alloc_one_kernel(struct mm_struct *mm,
+ unsigned long address)
{
- pgd_t *pgd;
-
- pgd = (pgd_t *)__get_free_pages(GFP_KERNEL|__GFP_ZERO, PGD_ORDER);
-
- if (likely(pgd != NULL))
- __flush_dcache_page((unsigned long)pgd);
+ return kmem_cache_alloc(pgtable_cache, GFP_KERNEL|__GFP_REPEAT);
+}
- return pgd;
+static inline struct page *pte_alloc_one(struct mm_struct *mm,
+ unsigned long addr)
+{
+ return virt_to_page(pte_alloc_one_kernel(mm, addr));
}
-extern pte_t* pte_alloc_one_kernel(struct mm_struct* mm, unsigned long addr);
-extern struct page* pte_alloc_one(struct mm_struct* mm, unsigned long addr);
+static inline void pte_free_kernel(pte_t *pte)
+{
+ kmem_cache_free(pgtable_cache, pte);
+}
-#define pte_free_kernel(pte) free_page((unsigned long)pte)
-#define pte_free(pte) __free_page(pte)
+static inline void pte_free(struct page *page)
+{
+ kmem_cache_free(pgtable_cache, page_address(page));
+}
#endif /* __KERNEL__ */
#endif /* _XTENSA_PGALLOC_H */
diff --git a/include/asm-xtensa/pgtable.h b/include/asm-xtensa/pgtable.h
index 06850f3b26a..c0fcc1c9660 100644
--- a/include/asm-xtensa/pgtable.h
+++ b/include/asm-xtensa/pgtable.h
@@ -1,11 +1,11 @@
/*
- * linux/include/asm-xtensa/pgtable.h
+ * include/asm-xtensa/pgtable.h
*
* This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version2 as
+ * it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
- * Copyright (C) 2001 - 2005 Tensilica Inc.
+ * Copyright (C) 2001 - 2007 Tensilica Inc.
*/
#ifndef _XTENSA_PGTABLE_H
@@ -23,7 +23,7 @@
/*
* The Xtensa architecture port of Linux has a two-level page table system,
- * i.e. the logical three-level Linux page table layout are folded.
+ * i.e. the logical three-level Linux page table layout is folded.
* Each task has the following memory page tables:
*
* PGD table (page directory), ie. 3rd-level page table:
@@ -43,6 +43,7 @@
*
* The individual pages are 4 kB big with special pages for the empty_zero_page.
*/
+
#define PGDIR_SHIFT 22
#define PGDIR_SIZE (1UL << PGDIR_SHIFT)
#define PGDIR_MASK (~(PGDIR_SIZE-1))
@@ -53,24 +54,26 @@
*/
#define PTRS_PER_PTE 1024
#define PTRS_PER_PTE_SHIFT 10
-#define PTRS_PER_PMD 1
#define PTRS_PER_PGD 1024
#define PGD_ORDER 0
-#define PMD_ORDER 0
#define USER_PTRS_PER_PGD (TASK_SIZE/PGDIR_SIZE)
-#define FIRST_USER_ADDRESS 0
+#define FIRST_USER_ADDRESS 0
#define FIRST_USER_PGD_NR (FIRST_USER_ADDRESS >> PGDIR_SHIFT)
-/* virtual memory area. We keep a distance to other memory regions to be
+/*
+ * Virtual memory area. We keep a distance to other memory regions to be
* on the safe side. We also use this area for cache aliasing.
*/
-// FIXME: virtual memory area must be configuration-dependent
-
#define VMALLOC_START 0xC0000000
-#define VMALLOC_END 0xC7FF0000
+#define VMALLOC_END 0xC6FEFFFF
+#define TLBTEMP_BASE_1 0xC6FF0000
+#define TLBTEMP_BASE_2 0xC6FF8000
+#define MODULE_START 0xC7000000
+#define MODULE_END 0xC7FFFFFF
-/* Xtensa Linux config PTE layout (when present):
+/*
+ * Xtensa Linux config PTE layout (when present):
* 31-12: PPN
* 11-6: Software
* 5-4: RING
@@ -86,47 +89,55 @@
* See further below for PTE layout for swapped-out pages.
*/
-#define _PAGE_VALID (1<<0) /* hardware: page is accessible */
-#define _PAGE_WRENABLE (1<<1) /* hardware: page is writable */
+#define _PAGE_HW_EXEC (1<<0) /* hardware: page is executable */
+#define _PAGE_HW_WRITE (1<<1) /* hardware: page is writable */
+
+#define _PAGE_FILE (1<<1) /* non-linear mapping, if !present */
+#define _PAGE_PROTNONE (3<<0) /* special case for VM_PROT_NONE */
/* None of these cache modes include MP coherency: */
-#define _PAGE_NO_CACHE (0<<2) /* bypass, non-speculative */
-#if XCHAL_DCACHE_IS_WRITEBACK
-# define _PAGE_WRITEBACK (1<<2) /* write back */
-# define _PAGE_WRITETHRU (2<<2) /* write through */
-#else
-# define _PAGE_WRITEBACK (1<<2) /* assume write through */
-# define _PAGE_WRITETHRU (1<<2)
-#endif
-#define _PAGE_NOALLOC (3<<2) /* don't allocate cache,if not cached */
-#define _CACHE_MASK (3<<2)
+#define _PAGE_CA_BYPASS (0<<2) /* bypass, non-speculative */
+#define _PAGE_CA_WB (1<<2) /* write-back */
+#define _PAGE_CA_WT (2<<2) /* write-through */
+#define _PAGE_CA_MASK (3<<2)
+#define _PAGE_INVALID (3<<2)
#define _PAGE_USER (1<<4) /* user access (ring=1) */
-#define _PAGE_KERNEL (0<<4) /* kernel access (ring=0) */
/* Software */
-#define _PAGE_RW (1<<6) /* software: page writable */
+#define _PAGE_WRITABLE_BIT 6
+#define _PAGE_WRITABLE (1<<6) /* software: page writable */
#define _PAGE_DIRTY (1<<7) /* software: page dirty */
#define _PAGE_ACCESSED (1<<8) /* software: page accessed (read) */
-#define _PAGE_FILE (1<<9) /* nonlinear file mapping*/
-#define _PAGE_CHG_MASK (PAGE_MASK | _PAGE_ACCESSED | _CACHE_MASK | _PAGE_DIRTY)
-#define _PAGE_PRESENT ( _PAGE_VALID | _PAGE_WRITEBACK | _PAGE_ACCESSED)
+/* On older HW revisions, we always have to set bit 0 */
+#if XCHAL_HW_VERSION_MAJOR < 2000
+# define _PAGE_VALID (1<<0)
+#else
+# define _PAGE_VALID 0
+#endif
-#ifdef CONFIG_MMU
+#define _PAGE_CHG_MASK (PAGE_MASK | _PAGE_ACCESSED | _PAGE_DIRTY)
+#define _PAGE_PRESENT (_PAGE_VALID | _PAGE_CA_WB | _PAGE_ACCESSED)
-# define PAGE_NONE __pgprot(_PAGE_PRESENT)
-# define PAGE_SHARED __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_RW)
-# define PAGE_COPY __pgprot(_PAGE_PRESENT | _PAGE_USER)
-# define PAGE_READONLY __pgprot(_PAGE_PRESENT | _PAGE_USER)
-# define PAGE_KERNEL __pgprot(_PAGE_PRESENT | _PAGE_KERNEL | _PAGE_WRENABLE)
-# define PAGE_INVALID __pgprot(_PAGE_USER)
+#ifdef CONFIG_MMU
-# if (DCACHE_WAY_SIZE > PAGE_SIZE)
-# define PAGE_DIRECTORY __pgprot(_PAGE_VALID | _PAGE_ACCESSED | _PAGE_KERNEL)
-# else
-# define PAGE_DIRECTORY __pgprot(_PAGE_PRESENT | _PAGE_KERNEL)
-# endif
+#define PAGE_NONE __pgprot(_PAGE_INVALID | _PAGE_USER | _PAGE_PROTNONE)
+#define PAGE_COPY __pgprot(_PAGE_PRESENT | _PAGE_USER)
+#define PAGE_COPY_EXEC __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_HW_EXEC)
+#define PAGE_READONLY __pgprot(_PAGE_PRESENT | _PAGE_USER)
+#define PAGE_READONLY_EXEC __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_HW_EXEC)
+#define PAGE_SHARED __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_WRITABLE)
+#define PAGE_SHARED_EXEC \
+ __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_WRITABLE | _PAGE_HW_EXEC)
+#define PAGE_KERNEL __pgprot(_PAGE_PRESENT | _PAGE_HW_WRITE)
+#define PAGE_KERNEL_EXEC __pgprot(_PAGE_PRESENT|_PAGE_HW_WRITE|_PAGE_HW_EXEC)
+
+#if (DCACHE_WAY_SIZE > PAGE_SIZE)
+# define _PAGE_DIRECTORY (_PAGE_VALID | _PAGE_ACCESSED)
+#else
+# define _PAGE_DIRECTORY (_PAGE_VALID | _PAGE_ACCESSED | _PAGE_CA_WB)
+#endif
#else /* no mmu */
@@ -145,23 +156,23 @@
* What follows is the closest we can get by reasonable means..
* See linux/mm/mmap.c for protection_map[] array that uses these definitions.
*/
-#define __P000 PAGE_NONE /* private --- */
-#define __P001 PAGE_READONLY /* private --r */
-#define __P010 PAGE_COPY /* private -w- */
-#define __P011 PAGE_COPY /* private -wr */
-#define __P100 PAGE_READONLY /* private x-- */
-#define __P101 PAGE_READONLY /* private x-r */
-#define __P110 PAGE_COPY /* private xw- */
-#define __P111 PAGE_COPY /* private xwr */
-
-#define __S000 PAGE_NONE /* shared --- */
-#define __S001 PAGE_READONLY /* shared --r */
-#define __S010 PAGE_SHARED /* shared -w- */
-#define __S011 PAGE_SHARED /* shared -wr */
-#define __S100 PAGE_READONLY /* shared x-- */
-#define __S101 PAGE_READONLY /* shared x-r */
-#define __S110 PAGE_SHARED /* shared xw- */
-#define __S111 PAGE_SHARED /* shared xwr */
+#define __P000 PAGE_NONE /* private --- */
+#define __P001 PAGE_READONLY /* private --r */
+#define __P010 PAGE_COPY /* private -w- */
+#define __P011 PAGE_COPY /* private -wr */
+#define __P100 PAGE_READONLY_EXEC /* private x-- */
+#define __P101 PAGE_READONLY_EXEC /* private x-r */
+#define __P110 PAGE_COPY_EXEC /* private xw- */
+#define __P111 PAGE_COPY_EXEC /* private xwr */
+
+#define __S000 PAGE_NONE /* shared --- */
+#define __S001 PAGE_READONLY /* shared --r */
+#define __S010 PAGE_SHARED /* shared -w- */
+#define __S011 PAGE_SHARED /* shared -wr */
+#define __S100 PAGE_READONLY_EXEC /* shared x-- */
+#define __S101 PAGE_READONLY_EXEC /* shared x-r */
+#define __S110 PAGE_SHARED_EXEC /* shared xw- */
+#define __S111 PAGE_SHARED_EXEC /* shared xwr */
#ifndef __ASSEMBLY__
@@ -183,35 +194,42 @@ extern pgd_t swapper_pg_dir[PAGE_SIZE/sizeof(pgd_t)];
#define pmd_page(pmd) virt_to_page(pmd_val(pmd))
/*
- * The following only work if pte_present() is true.
+ * pte status.
*/
-#define pte_none(pte) (!(pte_val(pte) ^ _PAGE_USER))
-#define pte_present(pte) (pte_val(pte) & _PAGE_VALID)
+#define pte_none(pte) (pte_val(pte) == _PAGE_INVALID)
+#define pte_present(pte) \
+ (((pte_val(pte) & _PAGE_CA_MASK) != _PAGE_INVALID) \
+ || ((pte_val(pte) & _PAGE_PROTNONE) == _PAGE_PROTNONE))
#define pte_clear(mm,addr,ptep) \
- do { update_pte(ptep, __pte(_PAGE_USER)); } while(0)
+ do { update_pte(ptep, __pte(_PAGE_INVALID)); } while(0)
#define pmd_none(pmd) (!pmd_val(pmd))
#define pmd_present(pmd) (pmd_val(pmd) & PAGE_MASK)
-#define pmd_clear(pmdp) do { set_pmd(pmdp, __pmd(0)); } while (0)
#define pmd_bad(pmd) (pmd_val(pmd) & ~PAGE_MASK)
+#define pmd_clear(pmdp) do { set_pmd(pmdp, __pmd(0)); } while (0)
-/* Note: We use the _PAGE_USER bit to indicate write-protect kernel memory */
-
-static inline int pte_write(pte_t pte) { return pte_val(pte) & _PAGE_RW; }
+static inline int pte_write(pte_t pte) { return pte_val(pte) & _PAGE_WRITABLE; }
static inline int pte_dirty(pte_t pte) { return pte_val(pte) & _PAGE_DIRTY; }
static inline int pte_young(pte_t pte) { return pte_val(pte) & _PAGE_ACCESSED; }
static inline int pte_file(pte_t pte) { return pte_val(pte) & _PAGE_FILE; }
-static inline pte_t pte_wrprotect(pte_t pte) { pte_val(pte) &= ~(_PAGE_RW | _PAGE_WRENABLE); return pte; }
-static inline pte_t pte_mkclean(pte_t pte) { pte_val(pte) &= ~_PAGE_DIRTY; return pte; }
-static inline pte_t pte_mkold(pte_t pte) { pte_val(pte) &= ~_PAGE_ACCESSED; return pte; }
-static inline pte_t pte_mkdirty(pte_t pte) { pte_val(pte) |= _PAGE_DIRTY; return pte; }
-static inline pte_t pte_mkyoung(pte_t pte) { pte_val(pte) |= _PAGE_ACCESSED; return pte; }
-static inline pte_t pte_mkwrite(pte_t pte) { pte_val(pte) |= _PAGE_RW; return pte; }
+static inline pte_t pte_wrprotect(pte_t pte)
+ { pte_val(pte) &= ~(_PAGE_WRITABLE | _PAGE_HW_WRITE); return pte; }
+static inline pte_t pte_mkclean(pte_t pte)
+ { pte_val(pte) &= ~(_PAGE_DIRTY | _PAGE_HW_WRITE); return pte; }
+static inline pte_t pte_mkold(pte_t pte)
+ { pte_val(pte) &= ~_PAGE_ACCESSED; return pte; }
+static inline pte_t pte_mkdirty(pte_t pte)
+ { pte_val(pte) |= _PAGE_DIRTY; return pte; }
+static inline pte_t pte_mkyoung(pte_t pte)
+ { pte_val(pte) |= _PAGE_ACCESSED; return pte; }
+static inline pte_t pte_mkwrite(pte_t pte)
+ { pte_val(pte) |= _PAGE_WRITABLE; return pte; }
/*
* Conversion functions: convert a page and protection to a page entry,
* and a page entry and page directory to the page they refer to.
*/
+
#define pte_pfn(pte) (pte_val(pte) >> PAGE_SHIFT)
#define pte_same(a,b) (pte_val(a) == pte_val(b))
#define pte_page(x) pfn_to_page(pte_pfn(x))
@@ -232,8 +250,9 @@ static inline void update_pte(pte_t *ptep, pte_t pteval)
{
*ptep = pteval;
#if (DCACHE_WAY_SIZE > PAGE_SIZE) && XCHAL_DCACHE_IS_WRITEBACK
- __asm__ __volatile__ ("memw; dhwb %0, 0; dsync" :: "a" (ptep));
+ __asm__ __volatile__ ("dhwb %0, 0" :: "a" (ptep));
#endif
+
}
struct mm_struct;
@@ -249,9 +268,6 @@ static inline void
set_pmd(pmd_t *pmdp, pmd_t pmdval)
{
*pmdp = pmdval;
-#if (DCACHE_WAY_SIZE > PAGE_SIZE) && XCHAL_DCACHE_IS_WRITEBACK
- __asm__ __volatile__ ("memw; dhwb %0, 0; dsync" :: "a" (pmdp));
-#endif
}
struct vm_area_struct;
@@ -306,52 +322,34 @@ ptep_set_wrprotect(struct mm_struct *mm, unsigned long addr, pte_t *ptep)
/*
* Encode and decode a swap entry.
- * Each PTE in a process VM's page table is either:
- * "present" -- valid and not swapped out, protection bits are meaningful;
- * "not present" -- which further subdivides in these two cases:
- * "none" -- no mapping at all; identified by pte_none(), set by pte_clear(
- * "swapped out" -- the page is swapped out, and the SWP macros below
- * are used to store swap file info in the PTE itself.
*
- * In the Xtensa processor MMU, any PTE entries in user space (or anywhere
- * in virtual memory that can map differently across address spaces)
- * must have a correct ring value that represents the RASID field that
- * is changed when switching address spaces. Eg. such PTE entries cannot
- * be set to ring zero, because that can cause a (global) kernel ASID
- * entry to be created in the TLBs (even with invalid cache attribute),
- * potentially causing a multihit exception when going back to another
- * address space that mapped the same virtual address at another ring.
- *
- * SO: we avoid using ring bits (_PAGE_RING_MASK) in "not present" PTEs.
- * We also avoid using the _PAGE_VALID bit which must be zero for non-present
- * pages.
- *
- * We end up with the following available bits: 1..3 and 7..31.
- * We don't bother with 1..3 for now (we can use them later if needed),
- * and chose to allocate 6 bits for SWP_TYPE and the remaining 19 bits
- * for SWP_OFFSET. At least 5 bits are needed for SWP_TYPE, because it
- * is currently implemented as an index into swap_info[MAX_SWAPFILES]
- * and MAX_SWAPFILES is currently defined as 32 in <linux/swap.h>.
- * However, for some reason all other architectures in the 2.4 kernel
- * reserve either 6, 7, or 8 bits so I'll not detract from that for now. :)
- * SWP_OFFSET is an offset into the swap file in page-size units, so
- * with 4 kB pages, 19 bits supports a maximum swap file size of 2 GB.
- *
- * FIXME: 2 GB isn't very big. Other bits can be used to allow
- * larger swap sizes. In the meantime, it appears relatively easy to get
- * around the 2 GB limitation by simply using multiple swap files.
+ * Format of swap pte:
+ * bit 0 MBZ
+ * bit 1 page-file (must be zero)
+ * bits 2 - 3 page hw access mode (must be 11: _PAGE_INVALID)
+ * bits 4 - 5 ring protection (must be 01: _PAGE_USER)
+ * bits 6 - 10 swap type (5 bits -> 32 types)
+ * bits 11 - 31 swap offset / PAGE_SIZE (21 bits -> 8GB)
+
+ * Format of file pte:
+ * bit 0 MBZ
+ * bit 1 page-file (must be one: _PAGE_FILE)
+ * bits 2 - 3 page hw access mode (must be 11: _PAGE_INVALID)
+ * bits 4 - 5 ring protection (must be 01: _PAGE_USER)
+ * bits 6 - 31 file offset / PAGE_SIZE
*/
-#define __swp_type(entry) (((entry).val >> 7) & 0x3f)
-#define __swp_offset(entry) ((entry).val >> 13)
-#define __swp_entry(type,offs) ((swp_entry_t) {((type) << 7) | ((offs) << 13)})
+#define __swp_type(entry) (((entry).val >> 6) & 0x1f)
+#define __swp_offset(entry) ((entry).val >> 11)
+#define __swp_entry(type,offs) \
+ ((swp_entry_t) {((type) << 6) | ((offs) << 11) | _PAGE_INVALID})
#define __pte_to_swp_entry(pte) ((swp_entry_t) { pte_val(pte) })
#define __swp_entry_to_pte(x) ((pte_t) { (x).val })
-#define PTE_FILE_MAX_BITS 29
-#define pte_to_pgoff(pte) (pte_val(pte) >> 3)
-#define pgoff_to_pte(off) ((pte_t) { ((off) << 3) | _PAGE_FILE })
-
+#define PTE_FILE_MAX_BITS 28
+#define pte_to_pgoff(pte) (pte_val(pte) >> 4)
+#define pgoff_to_pte(off) \
+ ((pte_t) { ((off) << 4) | _PAGE_INVALID | _PAGE_FILE })
#endif /* !defined (__ASSEMBLY__) */
@@ -394,13 +392,12 @@ extern void update_mmu_cache(struct vm_area_struct * vma,
* remap a physical page `pfn' of size `size' with page protection `prot'
* into virtual address `from'
*/
+
#define io_remap_pfn_range(vma,from,pfn,size,prot) \
remap_pfn_range(vma, from, pfn, size, prot)
-/* No page table caches to init */
-
-#define pgtable_cache_init() do { } while (0)
+extern void pgtable_cache_init(void);
typedef pte_t *pte_addr_t;
diff --git a/include/asm-xtensa/processor.h b/include/asm-xtensa/processor.h
index 4feb9f7f35a..35145bcd96e 100644
--- a/include/asm-xtensa/processor.h
+++ b/include/asm-xtensa/processor.h
@@ -33,7 +33,7 @@
* the 1 GB requirement applies to the stack as well.
*/
-#define TASK_SIZE 0x40000000
+#define TASK_SIZE __XTENSA_UL_CONST(0x40000000)
/*
* General exception cause assigned to debug exceptions. Debug exceptions go
diff --git a/include/asm-xtensa/syscall.h b/include/asm-xtensa/syscall.h
index 6cb0d42f11c..05cebf8f62b 100644
--- a/include/asm-xtensa/syscall.h
+++ b/include/asm-xtensa/syscall.h
@@ -1,3 +1,13 @@
+/*
+ * include/asm-xtensa/syscall.h
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2001 - 2007 Tensilica Inc.
+ */
+
struct pt_regs;
struct sigaction;
asmlinkage long xtensa_execve(char*, char**, char**, struct pt_regs*);
@@ -17,4 +27,16 @@ asmlinkage long sys_rt_sigaction(int,
const struct sigaction __user *,
struct sigaction __user *,
size_t);
-asmlinkage long xtensa_shmat(int shmid, char __user *shmaddr, int shmflg);
+asmlinkage long xtensa_shmat(int, char __user *, int);
+asmlinkage long xtensa_fadvise64_64(int, int,
+ unsigned long long, unsigned long long);
+
+/* Should probably move to linux/syscalls.h */
+struct pollfd;
+asmlinkage long sys_pselect6(int n, fd_set __user *inp, fd_set __user *outp,
+ fd_set __user *exp, struct timespec __user *tsp, void __user *sig);
+asmlinkage long sys_ppoll(struct pollfd __user *ufds, unsigned int nfds,
+ struct timespec __user *tsp, const sigset_t __user *sigmask,
+ size_t sigsetsize);
+
+
diff --git a/include/asm-xtensa/termbits.h b/include/asm-xtensa/termbits.h
index 9972c25ec86..85aa6a3c0b6 100644
--- a/include/asm-xtensa/termbits.h
+++ b/include/asm-xtensa/termbits.h
@@ -157,6 +157,7 @@ struct ktermios {
#define HUPCL 0002000
#define CLOCAL 0004000
#define CBAUDEX 0010000
+#define BOTHER 0010000
#define B57600 0010001
#define B115200 0010002
#define B230400 0010003
@@ -172,10 +173,12 @@ struct ktermios {
#define B3000000 0010015
#define B3500000 0010016
#define B4000000 0010017
-#define CIBAUD 002003600000 /* input baud rate (not used) */
+#define CIBAUD 002003600000 /* input baud rate */
#define CMSPAR 010000000000 /* mark or space (stick) parity */
#define CRTSCTS 020000000000 /* flow control */
+#define IBSHIFT 16 /* Shift from CBAUD to CIBAUD */
+
/* c_lflag bits */
#define ISIG 0000001
diff --git a/include/asm-xtensa/termios.h b/include/asm-xtensa/termios.h
index f14b42c8dac..4673f42f88a 100644
--- a/include/asm-xtensa/termios.h
+++ b/include/asm-xtensa/termios.h
@@ -95,8 +95,10 @@ struct termio {
copy_to_user((termio)->c_cc, (termios)->c_cc, NCC); \
})
-#define user_termios_to_kernel_termios(k, u) copy_from_user(k, u, sizeof(struct termios))
-#define kernel_termios_to_user_termios(u, k) copy_to_user(u, k, sizeof(struct termios))
+#define user_termios_to_kernel_termios(k, u) copy_from_user(k, u, sizeof(struct termios2))
+#define kernel_termios_to_user_termios(u, k) copy_to_user(u, k, sizeof(struct termios2))
+#define user_termios_to_kernel_termios_1(k, u) copy_from_user(k, u, sizeof(struct termios))
+#define kernel_termios_to_user_termios_1(u, k) copy_to_user(u, k, sizeof(struct termios))
#endif /* __KERNEL__ */
diff --git a/include/asm-xtensa/timex.h b/include/asm-xtensa/timex.h
index 28c7985a400..a5fca59fba9 100644
--- a/include/asm-xtensa/timex.h
+++ b/include/asm-xtensa/timex.h
@@ -41,10 +41,10 @@
extern unsigned long ccount_per_jiffy;
extern unsigned long ccount_nsec;
#define CCOUNT_PER_JIFFY ccount_per_jiffy
-#define CCOUNT_NSEC ccount_nsec
+#define NSEC_PER_CCOUNT ccount_nsec
#else
#define CCOUNT_PER_JIFFY (CONFIG_XTENSA_CPU_CLOCK*(1000000UL/HZ))
-#define CCOUNT_NSEC (1000000000UL / CONFIG_XTENSA_CPU_CLOCK)
+#define NSEC_PER_CCOUNT (1000UL / CONFIG_XTENSA_CPU_CLOCK)
#endif
diff --git a/include/asm-xtensa/tlb.h b/include/asm-xtensa/tlb.h
index 4562b2dcfbc..4830232017a 100644
--- a/include/asm-xtensa/tlb.h
+++ b/include/asm-xtensa/tlb.h
@@ -11,14 +11,36 @@
#ifndef _XTENSA_TLB_H
#define _XTENSA_TLB_H
-#define tlb_start_vma(tlb,vma) do { } while (0)
-#define tlb_end_vma(tlb,vma) do { } while (0)
-#define __tlb_remove_tlb_entry(tlb,pte,addr) do { } while (0)
+#include <asm/cache.h>
+#include <asm/page.h>
+
+#if (DCACHE_WAY_SIZE <= PAGE_SIZE)
+
+/* Note, read http://lkml.org/lkml/2004/1/15/6 */
+
+# define tlb_start_vma(tlb,vma) do { } while (0)
+# define tlb_end_vma(tlb,vma) do { } while (0)
+
+#else
+# define tlb_start_vma(tlb, vma) \
+ do { \
+ if (!tlb->fullmm) \
+ flush_cache_range(vma, vma->vm_start, vma->vm_end); \
+ } while(0)
+
+# define tlb_end_vma(tlb, vma) \
+ do { \
+ if (!tlb->fullmm) \
+ flush_tlb_range(vma, vma->vm_start, vma->vm_end); \
+ } while(0)
+
+#endif
+
+#define __tlb_remove_tlb_entry(tlb,pte,addr) do { } while (0)
#define tlb_flush(tlb) flush_tlb_mm((tlb)->mm)
#include <asm-generic/tlb.h>
-#include <asm/page.h>
#define __pte_free_tlb(tlb,pte) pte_free(pte)
diff --git a/include/asm-xtensa/types.h b/include/asm-xtensa/types.h
index 9d99a8e9e33..f1e84526f99 100644
--- a/include/asm-xtensa/types.h
+++ b/include/asm-xtensa/types.h
@@ -11,6 +11,15 @@
#ifndef _XTENSA_TYPES_H
#define _XTENSA_TYPES_H
+
+#ifdef __ASSEMBLY__
+# define __XTENSA_UL(x) (x)
+# define __XTENSA_UL_CONST(x) x
+#else
+# define __XTENSA_UL(x) ((unsigned long)(x))
+# define __XTENSA_UL_CONST(x) x##UL
+#endif
+
#ifndef __ASSEMBLY__
typedef unsigned short umode_t;
diff --git a/include/asm-xtensa/unistd.h b/include/asm-xtensa/unistd.h
index 9bd34024431..92968aabe34 100644
--- a/include/asm-xtensa/unistd.h
+++ b/include/asm-xtensa/unistd.h
@@ -151,7 +151,7 @@ __SYSCALL( 61, sys_fcntl64, 3)
#define __NR_available62 62
__SYSCALL( 62, sys_ni_syscall, 0)
#define __NR_fadvise64_64 63
-__SYSCALL( 63, sys_fadvise64_64, 6)
+__SYSCALL( 63, xtensa_fadvise64_64, 6)
#define __NR_utime 64 /* glibc 2.3.3 ?? */
__SYSCALL( 64, sys_utime, 2)
#define __NR_utimes 65
@@ -339,8 +339,8 @@ __SYSCALL(148, sys_setpgid, 2)
__SYSCALL(149, sys_getpgid, 1)
#define __NR_getppid 150
__SYSCALL(150, sys_getppid, 0)
-#define __NR_available151 151
-__SYSCALL(151, sys_ni_syscall, 0)
+#define __NR_getpgrp 151
+__SYSCALL(151, sys_getpgrp, 0)
#define __NR_reserved152 152 /* set_thread_area */
__SYSCALL(152, sys_ni_syscall, 0)
@@ -577,7 +577,112 @@ __SYSCALL(258, sys_keyctl, 5)
#define __NR_available259 259
__SYSCALL(259, sys_ni_syscall, 0)
-#define __NR_syscall_count 261
+
+#define __NR_readahead 260
+__SYSCALL(260, sys_readahead, 5)
+#define __NR_remap_file_pages 261
+__SYSCALL(261, sys_remap_file_pages, 5)
+#define __NR_migrate_pages 262
+__SYSCALL(262, sys_migrate_pages, 0)
+#define __NR_mbind 263
+__SYSCALL(263, sys_mbind, 6)
+#define __NR_get_mempolicy 264
+__SYSCALL(264, sys_get_mempolicy, 5)
+#define __NR_set_mempolicy 265
+__SYSCALL(265, sys_set_mempolicy, 3)
+#define __NR_unshare 266
+__SYSCALL(266, sys_unshare, 1)
+#define __NR_move_pages 267
+__SYSCALL(267, sys_move_pages, 0)
+#define __NR_splice 268
+__SYSCALL(268, sys_splice, 0)
+#define __NR_tee 269
+__SYSCALL(269, sys_tee, 0)
+#define __NR_vmsplice 270
+__SYSCALL(270, sys_vmsplice, 0)
+#define __NR_available271 271
+__SYSCALL(271, sys_ni_syscall, 0)
+
+#define __NR_pselect6 272
+__SYSCALL(272, sys_pselect6, 0)
+#define __NR_ppoll 273
+__SYSCALL(273, sys_ppoll, 0)
+#define __NR_epoll_pwait 274
+__SYSCALL(274, sys_epoll_pwait, 0)
+#define __NR_available275 275
+__SYSCALL(275, sys_ni_syscall, 0)
+
+#define __NR_inotify_init 276
+__SYSCALL(276, sys_inotify_init, 0)
+#define __NR_inotify_add_watch 277
+__SYSCALL(277, sys_inotify_add_watch, 3)
+#define __NR_inotify_rm_watch 278
+__SYSCALL(278, sys_inotify_rm_watch, 2)
+#define __NR_available279 279
+__SYSCALL(279, sys_ni_syscall, 0)
+
+#define __NR_getcpu 280
+__SYSCALL(280, sys_getcpu, 0)
+#define __NR_kexec_load 281
+__SYSCALL(281, sys_ni_syscall, 0)
+
+#define __NR_ioprio_set 282
+__SYSCALL(282, sys_ioprio_set, 2)
+#define __NR_ioprio_get 283
+__SYSCALL(283, sys_ioprio_get, 3)
+
+#define __NR_set_robust_list 284
+__SYSCALL(284, sys_set_robust_list, 3)
+#define __NR_get_robust_list 285
+__SYSCALL(285, sys_get_robust_list, 3)
+#define __NR_reserved286 286 /* sync_file_rangeX */
+__SYSCALL(286, sys_ni_syscall, 3)
+#define __NR_available287 287
+__SYSCALL(287, sys_faccessat, 0)
+
+/* Relative File Operations */
+
+#define __NR_openat 288
+__SYSCALL(288, sys_openat, 4)
+#define __NR_mkdirat 289
+__SYSCALL(289, sys_mkdirat, 3)
+#define __NR_mknodat 290
+__SYSCALL(290, sys_mknodat, 4)
+#define __NR_unlinkat 291
+__SYSCALL(291, sys_unlinkat, 3)
+#define __NR_renameat 292
+__SYSCALL(292, sys_renameat, 4)
+#define __NR_linkat 293
+__SYSCALL(293, sys_linkat, 5)
+#define __NR_symlinkat 294
+__SYSCALL(294, sys_symlinkat, 3)
+#define __NR_readlinkat 295
+__SYSCALL(295, sys_readlinkat, 4)
+#define __NR_utimensat 296
+__SYSCALL(296, sys_utimensat, 0)
+#define __NR_fchownat 297
+__SYSCALL(297, sys_fchownat, 5)
+#define __NR_futimesat 298
+__SYSCALL(298, sys_futimesat, 4)
+#define __NR_fstatat64 299
+__SYSCALL(299, sys_fstatat64, 0)
+#define __NR_fchmodat 300
+__SYSCALL(300, sys_fchmodat, 4)
+#define __NR_faccessat 301
+__SYSCALL(301, sys_faccessat, 4)
+#define __NR_available302 302
+__SYSCALL(302, sys_ni_syscall, 0)
+#define __NR_available303 303
+__SYSCALL(303, sys_ni_syscall, 0)
+
+#define __NR_signalfd 304
+__SYSCALL(304, sys_signalfd, 3)
+#define __NR_timerfd 305
+__SYSCALL(305, sys_timerfd, 4)
+#define __NR_eventfd 306
+__SYSCALL(306, sys_eventfd, 1)
+
+#define __NR_syscall_count 307
/*
* sysxtensa syscall handler
@@ -612,8 +717,19 @@ __SYSCALL(259, sys_ni_syscall, 0)
#define __ARCH_WANT_SYS_LLSEEK
#define __ARCH_WANT_SYS_RT_SIGACTION
#define __ARCH_WANT_SYS_RT_SIGSUSPEND
+#define __ARCH_WANT_SYS_GETPGRP
-#endif /* __KERNEL__ */
+/*
+ * Ignore legacy system calls in the checksyscalls.sh script
+ */
-#endif /* _XTENSA_UNISTD_H */
+#define __IGNORE_fork /* use clone */
+#define __IGNORE_time
+#define __IGNORE_alarm /* use setitimer */
+#define __IGNORE_pause
+#define __IGNORE_mmap /* use mmap2 */
+#define __IGNORE_vfork /* use clone */
+#define __IGNORE_fadvise64 /* use fadvise64_64 */
+#endif /* __KERNEL__ */
+#endif /* _XTENSA_UNISTD_H */
diff --git a/include/linux/isa.h b/include/linux/isa.h
index 1b855335cb1..b0270e3814c 100644
--- a/include/linux/isa.h
+++ b/include/linux/isa.h
@@ -22,7 +22,18 @@ struct isa_driver {
#define to_isa_driver(x) container_of((x), struct isa_driver, driver)
+#ifdef CONFIG_ISA
int isa_register_driver(struct isa_driver *, unsigned int);
void isa_unregister_driver(struct isa_driver *);
+#else
+static inline int isa_register_driver(struct isa_driver *d, unsigned int i)
+{
+ return 0;
+}
+
+static inline void isa_unregister_driver(struct isa_driver *d)
+{
+}
+#endif
#endif /* __LINUX_ISA_H */
diff --git a/include/linux/mempolicy.h b/include/linux/mempolicy.h
index 5bdd656e88c..a020eb2d4e2 100644
--- a/include/linux/mempolicy.h
+++ b/include/linux/mempolicy.h
@@ -159,7 +159,7 @@ extern void mpol_fix_fork_child_flag(struct task_struct *p);
extern struct mempolicy default_policy;
extern struct zonelist *huge_zonelist(struct vm_area_struct *vma,
- unsigned long addr, gfp_t gfp_flags);
+ unsigned long addr, gfp_t gfp_flags, struct mempolicy **mpol);
extern unsigned slab_node(struct mempolicy *policy);
extern enum zone_type policy_zone;
@@ -256,7 +256,7 @@ static inline void mpol_fix_fork_child_flag(struct task_struct *p)
#define set_cpuset_being_rebound(x) do {} while (0)
static inline struct zonelist *huge_zonelist(struct vm_area_struct *vma,
- unsigned long addr, gfp_t gfp_flags)
+ unsigned long addr, gfp_t gfp_flags, struct mempolicy **mpol)
{
return NODE_DATA(0)->node_zonelists + gfp_zone(gfp_flags);
}
diff --git a/include/linux/sched.h b/include/linux/sched.h
index f4e324ed2e4..5445eaec690 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -593,7 +593,7 @@ struct user_struct {
#endif
/* Hash table maintenance information */
- struct list_head uidhash_list;
+ struct hlist_node uidhash_node;
uid_t uid;
};
@@ -1472,6 +1472,7 @@ static inline struct user_struct *get_uid(struct user_struct *u)
}
extern void free_uid(struct user_struct *);
extern void switch_uid(struct user_struct *);
+extern void release_uids(struct user_namespace *ns);
#include <asm/current.h>
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
index 93c27f71122..a656cecd373 100644
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -1352,6 +1352,22 @@ static inline int skb_clone_writable(struct sk_buff *skb, int len)
skb_headroom(skb) + len <= skb->hdr_len;
}
+static inline int __skb_cow(struct sk_buff *skb, unsigned int headroom,
+ int cloned)
+{
+ int delta = 0;
+
+ if (headroom < NET_SKB_PAD)
+ headroom = NET_SKB_PAD;
+ if (headroom > skb_headroom(skb))
+ delta = headroom - skb_headroom(skb);
+
+ if (delta || cloned)
+ return pskb_expand_head(skb, ALIGN(delta, NET_SKB_PAD), 0,
+ GFP_ATOMIC);
+ return 0;
+}
+
/**
* skb_cow - copy header of skb when it is required
* @skb: buffer to cow
@@ -1366,16 +1382,22 @@ static inline int skb_clone_writable(struct sk_buff *skb, int len)
*/
static inline int skb_cow(struct sk_buff *skb, unsigned int headroom)
{
- int delta = (headroom > NET_SKB_PAD ? headroom : NET_SKB_PAD) -
- skb_headroom(skb);
-
- if (delta < 0)
- delta = 0;
+ return __skb_cow(skb, headroom, skb_cloned(skb));
+}
- if (delta || skb_cloned(skb))
- return pskb_expand_head(skb, (delta + (NET_SKB_PAD-1)) &
- ~(NET_SKB_PAD-1), 0, GFP_ATOMIC);
- return 0;
+/**
+ * skb_cow_head - skb_cow but only making the head writable
+ * @skb: buffer to cow
+ * @headroom: needed headroom
+ *
+ * This function is identical to skb_cow except that we replace the
+ * skb_cloned check by skb_header_cloned. It should be used when
+ * you only need to push on some header and do not need to modify
+ * the data.
+ */
+static inline int skb_cow_head(struct sk_buff *skb, unsigned int headroom)
+{
+ return __skb_cow(skb, headroom, skb_header_cloned(skb));
}
/**
diff --git a/include/linux/user_namespace.h b/include/linux/user_namespace.h
index 1101b0ce878..b5f41d4c2ee 100644
--- a/include/linux/user_namespace.h
+++ b/include/linux/user_namespace.h
@@ -11,7 +11,7 @@
struct user_namespace {
struct kref kref;
- struct list_head uidhash_table[UIDHASH_SZ];
+ struct hlist_head uidhash_table[UIDHASH_SZ];
struct user_struct *root_user;
};
diff --git a/include/media/v4l2-dev.h b/include/media/v4l2-dev.h
index d62847f846c..17f8f3a2f0a 100644
--- a/include/media/v4l2-dev.h
+++ b/include/media/v4l2-dev.h
@@ -337,6 +337,9 @@ void *priv;
struct class_device class_dev; /* sysfs */
};
+/* Class-dev to video-device */
+#define to_video_device(cd) container_of(cd, struct video_device, class_dev)
+
/* Version 2 functions */
extern int video_register_device(struct video_device *vfd, int type, int nr);
void video_unregister_device(struct video_device *);
@@ -354,11 +357,9 @@ extern int video_usercopy(struct inode *inode, struct file *file,
int (*func)(struct inode *inode, struct file *file,
unsigned int cmd, void *arg));
-
#ifdef CONFIG_VIDEO_V4L1_COMPAT
#include <linux/mm.h>
-#define to_video_device(cd) container_of(cd, struct video_device, class_dev)
static inline int __must_check
video_device_create_file(struct video_device *vfd,
struct class_device_attribute *attr)
diff --git a/include/net/sctp/sctp.h b/include/net/sctp/sctp.h
index d529045c167..c9cc00c8578 100644
--- a/include/net/sctp/sctp.h
+++ b/include/net/sctp/sctp.h
@@ -123,6 +123,7 @@
* sctp/protocol.c
*/
extern struct sock *sctp_get_ctl_sock(void);
+extern void sctp_local_addr_free(struct rcu_head *head);
extern int sctp_copy_local_addr_list(struct sctp_bind_addr *,
sctp_scope_t, gfp_t gfp,
int flags);
diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h
index c0d5848c33d..c2fe2dcc9af 100644
--- a/include/net/sctp/structs.h
+++ b/include/net/sctp/structs.h
@@ -207,6 +207,9 @@ extern struct sctp_globals {
* It is a list of sctp_sockaddr_entry.
*/
struct list_head local_addr_list;
+
+ /* Lock that protects the local_addr_list writers */
+ spinlock_t addr_list_lock;
/* Flag to indicate if addip is enabled. */
int addip_enable;
@@ -242,6 +245,7 @@ extern struct sctp_globals {
#define sctp_port_alloc_lock (sctp_globals.port_alloc_lock)
#define sctp_port_hashtable (sctp_globals.port_hashtable)
#define sctp_local_addr_list (sctp_globals.local_addr_list)
+#define sctp_local_addr_lock (sctp_globals.addr_list_lock)
#define sctp_addip_enable (sctp_globals.addip_enable)
#define sctp_prsctp_enable (sctp_globals.prsctp_enable)
@@ -737,8 +741,10 @@ const union sctp_addr *sctp_source(const struct sctp_chunk *chunk);
/* This is a structure for holding either an IPv6 or an IPv4 address. */
struct sctp_sockaddr_entry {
struct list_head list;
+ struct rcu_head rcu;
union sctp_addr a;
__u8 use_as_src;
+ __u8 valid;
};
typedef struct sctp_chunk *(sctp_packet_phandler_t)(struct sctp_association *);
@@ -1149,7 +1155,9 @@ int sctp_bind_addr_copy(struct sctp_bind_addr *dest,
int flags);
int sctp_add_bind_addr(struct sctp_bind_addr *, union sctp_addr *,
__u8 use_as_src, gfp_t gfp);
-int sctp_del_bind_addr(struct sctp_bind_addr *, union sctp_addr *);
+int sctp_del_bind_addr(struct sctp_bind_addr *, union sctp_addr *,
+ void (*rcu_call)(struct rcu_head *,
+ void (*func)(struct rcu_head *)));
int sctp_bind_addr_match(struct sctp_bind_addr *, const union sctp_addr *,
struct sctp_sock *);
union sctp_addr *sctp_find_unmatch_addr(struct sctp_bind_addr *bp,
@@ -1220,9 +1228,6 @@ struct sctp_ep_common {
* bind_addr.address_list is our set of local IP addresses.
*/
struct sctp_bind_addr bind_addr;
-
- /* Protection during address list comparisons. */
- rwlock_t addr_lock;
};
diff --git a/init/Kconfig b/init/Kconfig
index 96b54595f1d..d54d0cadcc0 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -488,6 +488,7 @@ config SIGNALFD
config TIMERFD
bool "Enable timerfd() system call" if EMBEDDED
select ANON_INODES
+ depends on BROKEN
default y
help
Enable the timerfd() system call that allows to receive timer
diff --git a/init/do_mounts_initrd.c b/init/do_mounts_initrd.c
index a6b4c0c08e1..fd4fc12d262 100644
--- a/init/do_mounts_initrd.c
+++ b/init/do_mounts_initrd.c
@@ -57,8 +57,10 @@ static void __init handle_initrd(void)
pid = kernel_thread(do_linuxrc, "/linuxrc", SIGCHLD);
if (pid > 0)
- while (pid != sys_wait4(-1, NULL, 0, NULL))
+ while (pid != sys_wait4(-1, NULL, 0, NULL)) {
+ try_to_freeze();
yield();
+ }
/* move initrd to rootfs' /old */
sys_fchdir(old_fd);
diff --git a/kernel/time/tick-broadcast.c b/kernel/time/tick-broadcast.c
index db8e0f3d409..aab881c86a1 100644
--- a/kernel/time/tick-broadcast.c
+++ b/kernel/time/tick-broadcast.c
@@ -382,12 +382,23 @@ static int tick_broadcast_set_event(ktime_t expires, int force)
int tick_resume_broadcast_oneshot(struct clock_event_device *bc)
{
+ int cpu = smp_processor_id();
+
+ /*
+ * If the CPU is marked for broadcast, enforce oneshot
+ * broadcast mode. The jinxed VAIO does not resume otherwise.
+ * No idea why it ends up in a lower C State during resume
+ * without notifying the clock events layer.
+ */
+ if (cpu_isset(cpu, tick_broadcast_mask))
+ cpu_set(cpu, tick_broadcast_oneshot_mask);
+
clockevents_set_mode(bc, CLOCK_EVT_MODE_ONESHOT);
if(!cpus_empty(tick_broadcast_oneshot_mask))
tick_broadcast_set_event(ktime_get(), 1);
- return cpu_isset(smp_processor_id(), tick_broadcast_oneshot_mask);
+ return cpu_isset(cpu, tick_broadcast_oneshot_mask);
}
/*
@@ -549,20 +560,17 @@ void tick_broadcast_switch_to_oneshot(void)
*/
void tick_shutdown_broadcast_oneshot(unsigned int *cpup)
{
- struct clock_event_device *bc;
unsigned long flags;
unsigned int cpu = *cpup;
spin_lock_irqsave(&tick_broadcast_lock, flags);
- bc = tick_broadcast_device.evtdev;
+ /*
+ * Clear the broadcast mask flag for the dead cpu, but do not
+ * stop the broadcast device!
+ */
cpu_clear(cpu, tick_broadcast_oneshot_mask);
- if (tick_broadcast_device.mode == TICKDEV_MODE_ONESHOT) {
- if (bc && cpus_empty(tick_broadcast_oneshot_mask))
- clockevents_set_mode(bc, CLOCK_EVT_MODE_SHUTDOWN);
- }
-
spin_unlock_irqrestore(&tick_broadcast_lock, flags);
}
diff --git a/kernel/time/tick-sched.c b/kernel/time/tick-sched.c
index b416995b975..8c3fef1db09 100644
--- a/kernel/time/tick-sched.c
+++ b/kernel/time/tick-sched.c
@@ -160,6 +160,18 @@ void tick_nohz_stop_sched_tick(void)
cpu = smp_processor_id();
ts = &per_cpu(tick_cpu_sched, cpu);
+ /*
+ * If this cpu is offline and it is the one which updates
+ * jiffies, then give up the assignment and let it be taken by
+ * the cpu which runs the tick timer next. If we don't drop
+ * this here the jiffies might be stale and do_timer() never
+ * invoked.
+ */
+ if (unlikely(!cpu_online(cpu))) {
+ if (cpu == tick_do_timer_cpu)
+ tick_do_timer_cpu = -1;
+ }
+
if (unlikely(ts->nohz_mode == NOHZ_MODE_INACTIVE))
goto end;
diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c
index acc417b5a9b..4ad79f6bdec 100644
--- a/kernel/time/timekeeping.c
+++ b/kernel/time/timekeeping.c
@@ -217,6 +217,7 @@ static void change_clocksource(void)
}
#else
static inline void change_clocksource(void) { }
+static inline s64 __get_nsec_offset(void) { return 0; }
#endif
/**
@@ -280,6 +281,8 @@ void __init timekeeping_init(void)
static int timekeeping_suspended;
/* time in seconds when suspend began */
static unsigned long timekeeping_suspend_time;
+/* xtime offset when we went into suspend */
+static s64 timekeeping_suspend_nsecs;
/**
* timekeeping_resume - Resumes the generic timekeeping subsystem.
@@ -305,6 +308,8 @@ static int timekeeping_resume(struct sys_device *dev)
wall_to_monotonic.tv_sec -= sleep_length;
total_sleep_time += sleep_length;
}
+ /* Make sure that we have the correct xtime reference */
+ timespec_add_ns(&xtime, timekeeping_suspend_nsecs);
/* re-base the last cycle value */
clock->cycle_last = clocksource_read(clock);
clock->error = 0;
@@ -325,9 +330,12 @@ static int timekeeping_suspend(struct sys_device *dev, pm_message_t state)
{
unsigned long flags;
+ timekeeping_suspend_time = read_persistent_clock();
+
write_seqlock_irqsave(&xtime_lock, flags);
+ /* Get the current xtime offset */
+ timekeeping_suspend_nsecs = __get_nsec_offset();
timekeeping_suspended = 1;
- timekeeping_suspend_time = read_persistent_clock();
write_sequnlock_irqrestore(&xtime_lock, flags);
clockevents_notify(CLOCK_EVT_NOTIFY_SUSPEND, NULL);
diff --git a/kernel/user.c b/kernel/user.c
index e7d11cef699..9ca2848fc35 100644
--- a/kernel/user.c
+++ b/kernel/user.c
@@ -55,25 +55,22 @@ struct user_struct root_user = {
/*
* These routines must be called with the uidhash spinlock held!
*/
-static inline void uid_hash_insert(struct user_struct *up, struct list_head *hashent)
+static inline void uid_hash_insert(struct user_struct *up, struct hlist_head *hashent)
{
- list_add(&up->uidhash_list, hashent);
+ hlist_add_head(&up->uidhash_node, hashent);
}
static inline void uid_hash_remove(struct user_struct *up)
{
- list_del(&up->uidhash_list);
+ hlist_del_init(&up->uidhash_node);
}
-static inline struct user_struct *uid_hash_find(uid_t uid, struct list_head *hashent)
+static inline struct user_struct *uid_hash_find(uid_t uid, struct hlist_head *hashent)
{
- struct list_head *up;
-
- list_for_each(up, hashent) {
- struct user_struct *user;
-
- user = list_entry(up, struct user_struct, uidhash_list);
+ struct user_struct *user;
+ struct hlist_node *h;
+ hlist_for_each_entry(user, h, hashent, uidhash_node) {
if(user->uid == uid) {
atomic_inc(&user->__count);
return user;
@@ -122,7 +119,7 @@ void free_uid(struct user_struct *up)
struct user_struct * alloc_uid(struct user_namespace *ns, uid_t uid)
{
- struct list_head *hashent = uidhashentry(ns, uid);
+ struct hlist_head *hashent = uidhashentry(ns, uid);
struct user_struct *up;
spin_lock_irq(&uidhash_lock);
@@ -202,6 +199,30 @@ void switch_uid(struct user_struct *new_user)
suid_keys(current);
}
+void release_uids(struct user_namespace *ns)
+{
+ int i;
+ unsigned long flags;
+ struct hlist_head *head;
+ struct hlist_node *nd;
+
+ spin_lock_irqsave(&uidhash_lock, flags);
+ /*
+ * collapse the chains so that the user_struct-s will
+ * be still alive, but not in hashes. subsequent free_uid()
+ * will free them.
+ */
+ for (i = 0; i < UIDHASH_SZ; i++) {
+ head = ns->uidhash_table + i;
+ while (!hlist_empty(head)) {
+ nd = head->first;
+ hlist_del_init(nd);
+ }
+ }
+ spin_unlock_irqrestore(&uidhash_lock, flags);
+
+ free_uid(ns->root_user);
+}
static int __init uid_cache_init(void)
{
@@ -211,7 +232,7 @@ static int __init uid_cache_init(void)
0, SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL);
for(n = 0; n < UIDHASH_SZ; ++n)
- INIT_LIST_HEAD(init_user_ns.uidhash_table + n);
+ INIT_HLIST_HEAD(init_user_ns.uidhash_table + n);
/* Insert the root user immediately (init already runs as root) */
spin_lock_irq(&uidhash_lock);
diff --git a/kernel/user_namespace.c b/kernel/user_namespace.c
index 85af9422ea6..7af90fc4f0f 100644
--- a/kernel/user_namespace.c
+++ b/kernel/user_namespace.c
@@ -39,7 +39,7 @@ static struct user_namespace *clone_user_ns(struct user_namespace *old_ns)
kref_init(&ns->kref);
for (n = 0; n < UIDHASH_SZ; ++n)
- INIT_LIST_HEAD(ns->uidhash_table + n);
+ INIT_HLIST_HEAD(ns->uidhash_table + n);
/* Insert new root user. */
ns->root_user = alloc_uid(ns, 0);
@@ -81,7 +81,7 @@ void free_user_ns(struct kref *kref)
struct user_namespace *ns;
ns = container_of(kref, struct user_namespace, kref);
- free_uid(ns->root_user);
+ release_uids(ns);
kfree(ns);
}
diff --git a/kernel/utsname.c b/kernel/utsname.c
index 9d8180a0f0d..816d7b24fa0 100644
--- a/kernel/utsname.c
+++ b/kernel/utsname.c
@@ -28,7 +28,9 @@ static struct uts_namespace *clone_uts_ns(struct uts_namespace *old_ns)
if (!ns)
return ERR_PTR(-ENOMEM);
+ down_read(&uts_sem);
memcpy(&ns->name, &old_ns->name, sizeof(ns->name));
+ up_read(&uts_sem);
kref_init(&ns->kref);
return ns;
}
diff --git a/mm/hugetlb.c b/mm/hugetlb.c
index de4cf458d6e..84c795ee2d6 100644
--- a/mm/hugetlb.c
+++ b/mm/hugetlb.c
@@ -71,8 +71,9 @@ static struct page *dequeue_huge_page(struct vm_area_struct *vma,
{
int nid;
struct page *page = NULL;
+ struct mempolicy *mpol;
struct zonelist *zonelist = huge_zonelist(vma, address,
- htlb_alloc_mask);
+ htlb_alloc_mask, &mpol);
struct zone **z;
for (z = zonelist->zones; *z; z++) {
@@ -87,6 +88,7 @@ static struct page *dequeue_huge_page(struct vm_area_struct *vma,
break;
}
}
+ mpol_free(mpol); /* unref if mpol !NULL */
return page;
}
diff --git a/mm/mempolicy.c b/mm/mempolicy.c
index bb54b88c3d5..3d6ac9505d0 100644
--- a/mm/mempolicy.c
+++ b/mm/mempolicy.c
@@ -1077,21 +1077,37 @@ asmlinkage long compat_sys_mbind(compat_ulong_t start, compat_ulong_t len,
#endif
-/* Return effective policy for a VMA */
+/*
+ * get_vma_policy(@task, @vma, @addr)
+ * @task - task for fallback if vma policy == default
+ * @vma - virtual memory area whose policy is sought
+ * @addr - address in @vma for shared policy lookup
+ *
+ * Returns effective policy for a VMA at specified address.
+ * Falls back to @task or system default policy, as necessary.
+ * Returned policy has extra reference count if shared, vma,
+ * or some other task's policy [show_numa_maps() can pass
+ * @task != current]. It is the caller's responsibility to
+ * free the reference in these cases.
+ */
static struct mempolicy * get_vma_policy(struct task_struct *task,
struct vm_area_struct *vma, unsigned long addr)
{
struct mempolicy *pol = task->mempolicy;
+ int shared_pol = 0;
if (vma) {
- if (vma->vm_ops && vma->vm_ops->get_policy)
+ if (vma->vm_ops && vma->vm_ops->get_policy) {
pol = vma->vm_ops->get_policy(vma, addr);
- else if (vma->vm_policy &&
+ shared_pol = 1; /* if pol non-NULL, add ref below */
+ } else if (vma->vm_policy &&
vma->vm_policy->policy != MPOL_DEFAULT)
pol = vma->vm_policy;
}
if (!pol)
pol = &default_policy;
+ else if (!shared_pol && pol != current->mempolicy)
+ mpol_get(pol); /* vma or other task's policy */
return pol;
}
@@ -1207,19 +1223,45 @@ static inline unsigned interleave_nid(struct mempolicy *pol,
}
#ifdef CONFIG_HUGETLBFS
-/* Return a zonelist suitable for a huge page allocation. */
+/*
+ * huge_zonelist(@vma, @addr, @gfp_flags, @mpol)
+ * @vma = virtual memory area whose policy is sought
+ * @addr = address in @vma for shared policy lookup and interleave policy
+ * @gfp_flags = for requested zone
+ * @mpol = pointer to mempolicy pointer for reference counted 'BIND policy
+ *
+ * Returns a zonelist suitable for a huge page allocation.
+ * If the effective policy is 'BIND, returns pointer to policy's zonelist.
+ * If it is also a policy for which get_vma_policy() returns an extra
+ * reference, we must hold that reference until after allocation.
+ * In that case, return policy via @mpol so hugetlb allocation can drop
+ * the reference. For non-'BIND referenced policies, we can/do drop the
+ * reference here, so the caller doesn't need to know about the special case
+ * for default and current task policy.
+ */
struct zonelist *huge_zonelist(struct vm_area_struct *vma, unsigned long addr,
- gfp_t gfp_flags)
+ gfp_t gfp_flags, struct mempolicy **mpol)
{
struct mempolicy *pol = get_vma_policy(current, vma, addr);
+ struct zonelist *zl;
+ *mpol = NULL; /* probably no unref needed */
if (pol->policy == MPOL_INTERLEAVE) {
unsigned nid;
nid = interleave_nid(pol, vma, addr, HPAGE_SHIFT);
+ __mpol_free(pol); /* finished with pol */
return NODE_DATA(nid)->node_zonelists + gfp_zone(gfp_flags);
}
- return zonelist_policy(GFP_HIGHUSER, pol);
+
+ zl = zonelist_policy(GFP_HIGHUSER, pol);
+ if (unlikely(pol != &default_policy && pol != current->mempolicy)) {
+ if (pol->policy != MPOL_BIND)
+ __mpol_free(pol); /* finished with pol */
+ else
+ *mpol = pol; /* unref needed after allocation */
+ }
+ return zl;
}
#endif
@@ -1264,6 +1306,7 @@ struct page *
alloc_page_vma(gfp_t gfp, struct vm_area_struct *vma, unsigned long addr)
{
struct mempolicy *pol = get_vma_policy(current, vma, addr);
+ struct zonelist *zl;
cpuset_update_task_memory_state();
@@ -1273,7 +1316,19 @@ alloc_page_vma(gfp_t gfp, struct vm_area_struct *vma, unsigned long addr)
nid = interleave_nid(pol, vma, addr, PAGE_SHIFT);
return alloc_page_interleave(gfp, 0, nid);
}
- return __alloc_pages(gfp, 0, zonelist_policy(gfp, pol));
+ zl = zonelist_policy(gfp, pol);
+ if (pol != &default_policy && pol != current->mempolicy) {
+ /*
+ * slow path: ref counted policy -- shared or vma
+ */
+ struct page *page = __alloc_pages(gfp, 0, zl);
+ __mpol_free(pol);
+ return page;
+ }
+ /*
+ * fast path: default or task policy
+ */
+ return __alloc_pages(gfp, 0, zl);
}
/**
@@ -1872,6 +1927,7 @@ int show_numa_map(struct seq_file *m, void *v)
struct numa_maps *md;
struct file *file = vma->vm_file;
struct mm_struct *mm = vma->vm_mm;
+ struct mempolicy *pol;
int n;
char buffer[50];
@@ -1882,8 +1938,13 @@ int show_numa_map(struct seq_file *m, void *v)
if (!md)
return 0;
- mpol_to_str(buffer, sizeof(buffer),
- get_vma_policy(priv->task, vma, vma->vm_start));
+ pol = get_vma_policy(priv->task, vma, vma->vm_start);
+ mpol_to_str(buffer, sizeof(buffer), pol);
+ /*
+ * unref shared or other task's mempolicy
+ */
+ if (pol != &default_policy && pol != current->mempolicy)
+ __mpol_free(pol);
seq_printf(m, "%08lx %s", vma->vm_start, buffer);
diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c
index 1583c5ef963..2a546919d6f 100644
--- a/net/8021q/vlan.c
+++ b/net/8021q/vlan.c
@@ -562,8 +562,6 @@ static int register_vlan_device(struct net_device *real_dev,
if (err < 0)
goto out_free_newdev;
- /* Account for reference in struct vlan_dev_info */
- dev_hold(real_dev);
#ifdef VLAN_DEBUG
printk(VLAN_DBG "Allocated new device successfully, returning.\n");
#endif
diff --git a/net/bridge/br_device.c b/net/bridge/br_device.c
index 0eded176ce9..99292e8e1d0 100644
--- a/net/bridge/br_device.c
+++ b/net/bridge/br_device.c
@@ -41,11 +41,11 @@ int br_dev_xmit(struct sk_buff *skb, struct net_device *dev)
skb_pull(skb, ETH_HLEN);
if (dest[0] & 1)
- br_flood_deliver(br, skb, 0);
+ br_flood_deliver(br, skb);
else if ((dst = __br_fdb_get(br, dest)) != NULL)
br_deliver(dst->dst, skb);
else
- br_flood_deliver(br, skb, 0);
+ br_flood_deliver(br, skb);
return 0;
}
diff --git a/net/bridge/br_forward.c b/net/bridge/br_forward.c
index ada7f495445..bdd7c35c3c7 100644
--- a/net/bridge/br_forward.c
+++ b/net/bridge/br_forward.c
@@ -100,24 +100,13 @@ void br_forward(const struct net_bridge_port *to, struct sk_buff *skb)
}
/* called under bridge lock */
-static void br_flood(struct net_bridge *br, struct sk_buff *skb, int clone,
+static void br_flood(struct net_bridge *br, struct sk_buff *skb,
void (*__packet_hook)(const struct net_bridge_port *p,
struct sk_buff *skb))
{
struct net_bridge_port *p;
struct net_bridge_port *prev;
- if (clone) {
- struct sk_buff *skb2;
-
- if ((skb2 = skb_clone(skb, GFP_ATOMIC)) == NULL) {
- br->statistics.tx_dropped++;
- return;
- }
-
- skb = skb2;
- }
-
prev = NULL;
list_for_each_entry_rcu(p, &br->port_list, list) {
@@ -148,13 +137,13 @@ static void br_flood(struct net_bridge *br, struct sk_buff *skb, int clone,
/* called with rcu_read_lock */
-void br_flood_deliver(struct net_bridge *br, struct sk_buff *skb, int clone)
+void br_flood_deliver(struct net_bridge *br, struct sk_buff *skb)
{
- br_flood(br, skb, clone, __br_deliver);
+ br_flood(br, skb, __br_deliver);
}
/* called under bridge lock */
-void br_flood_forward(struct net_bridge *br, struct sk_buff *skb, int clone)
+void br_flood_forward(struct net_bridge *br, struct sk_buff *skb)
{
- br_flood(br, skb, clone, __br_forward);
+ br_flood(br, skb, __br_forward);
}
diff --git a/net/bridge/br_input.c b/net/bridge/br_input.c
index 6f468fc3357..3a8a015c92e 100644
--- a/net/bridge/br_input.c
+++ b/net/bridge/br_input.c
@@ -43,7 +43,7 @@ int br_handle_frame_finish(struct sk_buff *skb)
struct net_bridge_port *p = rcu_dereference(skb->dev->br_port);
struct net_bridge *br;
struct net_bridge_fdb_entry *dst;
- int passedup = 0;
+ struct sk_buff *skb2;
if (!p || p->state == BR_STATE_DISABLED)
goto drop;
@@ -55,39 +55,35 @@ int br_handle_frame_finish(struct sk_buff *skb)
if (p->state == BR_STATE_LEARNING)
goto drop;
- if (br->dev->flags & IFF_PROMISC) {
- struct sk_buff *skb2;
+ /* The packet skb2 goes to the local host (NULL to skip). */
+ skb2 = NULL;
- skb2 = skb_clone(skb, GFP_ATOMIC);
- if (skb2 != NULL) {
- passedup = 1;
- br_pass_frame_up(br, skb2);
- }
- }
+ if (br->dev->flags & IFF_PROMISC)
+ skb2 = skb;
+
+ dst = NULL;
if (is_multicast_ether_addr(dest)) {
br->statistics.multicast++;
- br_flood_forward(br, skb, !passedup);
- if (!passedup)
- br_pass_frame_up(br, skb);
- goto out;
+ skb2 = skb;
+ } else if ((dst = __br_fdb_get(br, dest)) && dst->is_local) {
+ skb2 = skb;
+ /* Do not forward the packet since it's local. */
+ skb = NULL;
}
- dst = __br_fdb_get(br, dest);
- if (dst != NULL && dst->is_local) {
- if (!passedup)
- br_pass_frame_up(br, skb);
- else
- kfree_skb(skb);
- goto out;
- }
+ if (skb2 == skb)
+ skb2 = skb_clone(skb, GFP_ATOMIC);
- if (dst != NULL) {
- br_forward(dst->dst, skb);
- goto out;
- }
+ if (skb2)
+ br_pass_frame_up(br, skb2);
- br_flood_forward(br, skb, 0);
+ if (skb) {
+ if (dst)
+ br_forward(dst->dst, skb);
+ else
+ br_flood_forward(br, skb);
+ }
out:
return 0;
diff --git a/net/bridge/br_netfilter.c b/net/bridge/br_netfilter.c
index 3ee2022928e..fc13130035e 100644
--- a/net/bridge/br_netfilter.c
+++ b/net/bridge/br_netfilter.c
@@ -183,7 +183,7 @@ int nf_bridge_copy_header(struct sk_buff *skb)
int err;
int header_size = ETH_HLEN + nf_bridge_encap_header_len(skb);
- err = skb_cow(skb, header_size);
+ err = skb_cow_head(skb, header_size);
if (err)
return err;
diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h
index 21bf3a9a03f..e6dc6f52990 100644
--- a/net/bridge/br_private.h
+++ b/net/bridge/br_private.h
@@ -170,12 +170,8 @@ extern int br_dev_queue_push_xmit(struct sk_buff *skb);
extern void br_forward(const struct net_bridge_port *to,
struct sk_buff *skb);
extern int br_forward_finish(struct sk_buff *skb);
-extern void br_flood_deliver(struct net_bridge *br,
- struct sk_buff *skb,
- int clone);
-extern void br_flood_forward(struct net_bridge *br,
- struct sk_buff *skb,
- int clone);
+extern void br_flood_deliver(struct net_bridge *br, struct sk_buff *skb);
+extern void br_flood_forward(struct net_bridge *br, struct sk_buff *skb);
/* br_if.c */
extern void br_port_carrier_check(struct net_bridge_port *p);
diff --git a/net/core/pktgen.c b/net/core/pktgen.c
index 36fdea71d74..803d0c8826a 100644
--- a/net/core/pktgen.c
+++ b/net/core/pktgen.c
@@ -111,6 +111,9 @@
*
* 802.1Q/Q-in-Q support by Francesco Fondelli (FF) <francesco.fondelli@gmail.com>
*
+ * Fixed src_mac command to set source mac of packet to value specified in
+ * command by Adit Ranadive <adit.262@gmail.com>
+ *
*/
#include <linux/sys.h>
#include <linux/types.h>
@@ -1451,8 +1454,11 @@ static ssize_t pktgen_if_write(struct file *file,
}
if (!strcmp(name, "src_mac")) {
char *v = valstr;
+ unsigned char old_smac[ETH_ALEN];
unsigned char *m = pkt_dev->src_mac;
+ memcpy(old_smac, pkt_dev->src_mac, ETH_ALEN);
+
len = strn_len(&user_buffer[i], sizeof(valstr) - 1);
if (len < 0) {
return len;
@@ -1481,6 +1487,10 @@ static ssize_t pktgen_if_write(struct file *file,
}
}
+ /* Set up Src MAC */
+ if (compare_ether_addr(old_smac, pkt_dev->src_mac))
+ memcpy(&(pkt_dev->hh[6]), pkt_dev->src_mac, ETH_ALEN);
+
sprintf(pg_result, "OK: srcmac");
return count;
}
diff --git a/net/core/sock.c b/net/core/sock.c
index cfed7d42c48..190de61cd64 100644
--- a/net/core/sock.c
+++ b/net/core/sock.c
@@ -362,6 +362,61 @@ struct dst_entry *sk_dst_check(struct sock *sk, u32 cookie)
}
EXPORT_SYMBOL(sk_dst_check);
+static int sock_bindtodevice(struct sock *sk, char __user *optval, int optlen)
+{
+ int ret = -ENOPROTOOPT;
+#ifdef CONFIG_NETDEVICES
+ char devname[IFNAMSIZ];
+ int index;
+
+ /* Sorry... */
+ ret = -EPERM;
+ if (!capable(CAP_NET_RAW))
+ goto out;
+
+ ret = -EINVAL;
+ if (optlen < 0)
+ goto out;
+
+ /* Bind this socket to a particular device like "eth0",
+ * as specified in the passed interface name. If the
+ * name is "" or the option length is zero the socket
+ * is not bound.
+ */
+ if (optlen > IFNAMSIZ - 1)
+ optlen = IFNAMSIZ - 1;
+ memset(devname, 0, sizeof(devname));
+
+ ret = -EFAULT;
+ if (copy_from_user(devname, optval, optlen))
+ goto out;
+
+ if (devname[0] == '\0') {
+ index = 0;
+ } else {
+ struct net_device *dev = dev_get_by_name(devname);
+
+ ret = -ENODEV;
+ if (!dev)
+ goto out;
+
+ index = dev->ifindex;
+ dev_put(dev);
+ }
+
+ lock_sock(sk);
+ sk->sk_bound_dev_if = index;
+ sk_dst_reset(sk);
+ release_sock(sk);
+
+ ret = 0;
+
+out:
+#endif
+
+ return ret;
+}
+
/*
* This is meant for all protocols to use and covers goings on
* at the socket level. Everything here is generic.
@@ -390,6 +445,9 @@ int sock_setsockopt(struct socket *sock, int level, int optname,
}
#endif
+ if (optname == SO_BINDTODEVICE)
+ return sock_bindtodevice(sk, optval, optlen);
+
if (optlen < sizeof(int))
return -EINVAL;
@@ -578,54 +636,6 @@ set_rcvbuf:
ret = sock_set_timeout(&sk->sk_sndtimeo, optval, optlen);
break;
-#ifdef CONFIG_NETDEVICES
- case SO_BINDTODEVICE:
- {
- char devname[IFNAMSIZ];
-
- /* Sorry... */
- if (!capable(CAP_NET_RAW)) {
- ret = -EPERM;
- break;
- }
-
- /* Bind this socket to a particular device like "eth0",
- * as specified in the passed interface name. If the
- * name is "" or the option length is zero the socket
- * is not bound.
- */
-
- if (!valbool) {
- sk->sk_bound_dev_if = 0;
- } else {
- if (optlen > IFNAMSIZ - 1)
- optlen = IFNAMSIZ - 1;
- memset(devname, 0, sizeof(devname));
- if (copy_from_user(devname, optval, optlen)) {
- ret = -EFAULT;
- break;
- }
-
- /* Remove any cached route for this socket. */
- sk_dst_reset(sk);
-
- if (devname[0] == '\0') {
- sk->sk_bound_dev_if = 0;
- } else {
- struct net_device *dev = dev_get_by_name(devname);
- if (!dev) {
- ret = -ENODEV;
- break;
- }
- sk->sk_bound_dev_if = dev->ifindex;
- dev_put(dev);
- }
- }
- break;
- }
-#endif
-
-
case SO_ATTACH_FILTER:
ret = -EINVAL;
if (optlen == sizeof(struct sock_fprog)) {
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
index 28355350fb6..69d4bd10f9c 100644
--- a/net/ipv4/udp.c
+++ b/net/ipv4/udp.c
@@ -505,6 +505,8 @@ send:
out:
up->len = 0;
up->pending = 0;
+ if (!err)
+ UDP_INC_STATS_USER(UDP_MIB_OUTDATAGRAMS, up->pcflag);
return err;
}
@@ -693,10 +695,8 @@ out:
ip_rt_put(rt);
if (free)
kfree(ipc.opt);
- if (!err) {
- UDP_INC_STATS_USER(UDP_MIB_OUTDATAGRAMS, is_udplite);
+ if (!err)
return len;
- }
/*
* ENOBUFS = no kernel mem, SOCK_NOSPACE = no sndbuf space. Reporting
* ENOBUFS might not be good (it's not tunable per se), but otherwise
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index 91ef3be5aba..45b4c82148a 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -1021,7 +1021,7 @@ int ipv6_dev_get_saddr(struct net_device *daddr_dev,
hiscore.rule++;
}
if (ipv6_saddr_preferred(score.addr_type) ||
- (((ifa_result->flags &
+ (((ifa->flags &
(IFA_F_DEPRECATED|IFA_F_OPTIMISTIC)) == 0))) {
score.attrs |= IPV6_SADDR_SCORE_PREFERRED;
if (!(hiscore.attrs & IPV6_SADDR_SCORE_PREFERRED)) {
diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c
index e27383d855d..77167afa345 100644
--- a/net/ipv6/raw.c
+++ b/net/ipv6/raw.c
@@ -882,11 +882,10 @@ back_from_confirm:
ip6_flush_pending_frames(sk);
else if (!(msg->msg_flags & MSG_MORE))
err = rawv6_push_pending_frames(sk, &fl, rp);
+ release_sock(sk);
}
done:
dst_release(dst);
- if (!inet->hdrincl)
- release_sock(sk);
out:
fl6_sock_release(flowlabel);
return err<0?err:len;
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c
index 4210951edb6..c347f3e30e2 100644
--- a/net/ipv6/udp.c
+++ b/net/ipv6/udp.c
@@ -555,6 +555,8 @@ static int udp_v6_push_pending_frames(struct sock *sk)
out:
up->len = 0;
up->pending = 0;
+ if (!err)
+ UDP6_INC_STATS_USER(UDP_MIB_OUTDATAGRAMS, up->pcflag);
return err;
}
@@ -823,10 +825,8 @@ do_append_data:
release_sock(sk);
out:
fl6_sock_release(flowlabel);
- if (!err) {
- UDP6_INC_STATS_USER(UDP_MIB_OUTDATAGRAMS, is_udplite);
+ if (!err)
return len;
- }
/*
* ENOBUFS = no kernel mem, SOCK_NOSPACE = no sndbuf space. Reporting
* ENOBUFS might not be good (it's not tunable per se), but otherwise
diff --git a/net/sched/act_api.c b/net/sched/act_api.c
index feef366cad5..72cdb0fade2 100644
--- a/net/sched/act_api.c
+++ b/net/sched/act_api.c
@@ -68,7 +68,7 @@ static int tcf_dump_walker(struct sk_buff *skb, struct netlink_callback *cb,
int err = 0, index = -1,i = 0, s_i = 0, n_i = 0;
struct rtattr *r ;
- read_lock(hinfo->lock);
+ read_lock_bh(hinfo->lock);
s_i = cb->args[0];
@@ -96,7 +96,7 @@ static int tcf_dump_walker(struct sk_buff *skb, struct netlink_callback *cb,
}
}
done:
- read_unlock(hinfo->lock);
+ read_unlock_bh(hinfo->lock);
if (n_i)
cb->args[0] += n_i;
return n_i;
@@ -156,13 +156,13 @@ struct tcf_common *tcf_hash_lookup(u32 index, struct tcf_hashinfo *hinfo)
{
struct tcf_common *p;
- read_lock(hinfo->lock);
+ read_lock_bh(hinfo->lock);
for (p = hinfo->htab[tcf_hash(index, hinfo->hmask)]; p;
p = p->tcfc_next) {
if (p->tcfc_index == index)
break;
}
- read_unlock(hinfo->lock);
+ read_unlock_bh(hinfo->lock);
return p;
}
diff --git a/net/sched/act_police.c b/net/sched/act_police.c
index 6085be57845..17f6f27e28a 100644
--- a/net/sched/act_police.c
+++ b/net/sched/act_police.c
@@ -56,7 +56,7 @@ static int tcf_act_police_walker(struct sk_buff *skb, struct netlink_callback *c
int err = 0, index = -1, i = 0, s_i = 0, n_i = 0;
struct rtattr *r;
- read_lock(&police_lock);
+ read_lock_bh(&police_lock);
s_i = cb->args[0];
@@ -85,7 +85,7 @@ static int tcf_act_police_walker(struct sk_buff *skb, struct netlink_callback *c
}
}
done:
- read_unlock(&police_lock);
+ read_unlock_bh(&police_lock);
if (n_i)
cb->args[0] += n_i;
return n_i;
diff --git a/net/sched/sch_cbq.c b/net/sched/sch_cbq.c
index e38c2839b25..cbef3bbfc20 100644
--- a/net/sched/sch_cbq.c
+++ b/net/sched/sch_cbq.c
@@ -380,7 +380,7 @@ cbq_enqueue(struct sk_buff *skb, struct Qdisc *sch)
{
struct cbq_sched_data *q = qdisc_priv(sch);
int len = skb->len;
- int ret;
+ int uninitialized_var(ret);
struct cbq_class *cl = cbq_classify(skb, sch, &ret);
#ifdef CONFIG_NET_CLS_ACT
diff --git a/net/sctp/associola.c b/net/sctp/associola.c
index 2ad1caf1ea4..9bad8ba0fed 100644
--- a/net/sctp/associola.c
+++ b/net/sctp/associola.c
@@ -99,7 +99,6 @@ static struct sctp_association *sctp_association_init(struct sctp_association *a
/* Initialize the bind addr area. */
sctp_bind_addr_init(&asoc->base.bind_addr, ep->base.bind_addr.port);
- rwlock_init(&asoc->base.addr_lock);
asoc->state = SCTP_STATE_CLOSED;
@@ -937,8 +936,6 @@ struct sctp_transport *sctp_assoc_is_match(struct sctp_association *asoc,
{
struct sctp_transport *transport;
- sctp_read_lock(&asoc->base.addr_lock);
-
if ((htons(asoc->base.bind_addr.port) == laddr->v4.sin_port) &&
(htons(asoc->peer.port) == paddr->v4.sin_port)) {
transport = sctp_assoc_lookup_paddr(asoc, paddr);
@@ -952,7 +949,6 @@ struct sctp_transport *sctp_assoc_is_match(struct sctp_association *asoc,
transport = NULL;
out:
- sctp_read_unlock(&asoc->base.addr_lock);
return transport;
}
@@ -1376,19 +1372,13 @@ int sctp_assoc_set_bind_addr_from_cookie(struct sctp_association *asoc,
int sctp_assoc_lookup_laddr(struct sctp_association *asoc,
const union sctp_addr *laddr)
{
- int found;
+ int found = 0;
- sctp_read_lock(&asoc->base.addr_lock);
if ((asoc->base.bind_addr.port == ntohs(laddr->v4.sin_port)) &&
sctp_bind_addr_match(&asoc->base.bind_addr, laddr,
- sctp_sk(asoc->base.sk))) {
+ sctp_sk(asoc->base.sk)))
found = 1;
- goto out;
- }
- found = 0;
-out:
- sctp_read_unlock(&asoc->base.addr_lock);
return found;
}
diff --git a/net/sctp/bind_addr.c b/net/sctp/bind_addr.c
index fdb287a9e2e..d35cbf5aae3 100644
--- a/net/sctp/bind_addr.c
+++ b/net/sctp/bind_addr.c
@@ -163,9 +163,15 @@ int sctp_add_bind_addr(struct sctp_bind_addr *bp, union sctp_addr *new,
addr->a.v4.sin_port = htons(bp->port);
addr->use_as_src = use_as_src;
+ addr->valid = 1;
INIT_LIST_HEAD(&addr->list);
- list_add_tail(&addr->list, &bp->address_list);
+ INIT_RCU_HEAD(&addr->rcu);
+
+ /* We always hold a socket lock when calling this function,
+ * and that acts as a writer synchronizing lock.
+ */
+ list_add_tail_rcu(&addr->list, &bp->address_list);
SCTP_DBG_OBJCNT_INC(addr);
return 0;
@@ -174,23 +180,35 @@ int sctp_add_bind_addr(struct sctp_bind_addr *bp, union sctp_addr *new,
/* Delete an address from the bind address list in the SCTP_bind_addr
* structure.
*/
-int sctp_del_bind_addr(struct sctp_bind_addr *bp, union sctp_addr *del_addr)
+int sctp_del_bind_addr(struct sctp_bind_addr *bp, union sctp_addr *del_addr,
+ void (*rcu_call)(struct rcu_head *head,
+ void (*func)(struct rcu_head *head)))
{
- struct list_head *pos, *temp;
- struct sctp_sockaddr_entry *addr;
+ struct sctp_sockaddr_entry *addr, *temp;
- list_for_each_safe(pos, temp, &bp->address_list) {
- addr = list_entry(pos, struct sctp_sockaddr_entry, list);
+ /* We hold the socket lock when calling this function,
+ * and that acts as a writer synchronizing lock.
+ */
+ list_for_each_entry_safe(addr, temp, &bp->address_list, list) {
if (sctp_cmp_addr_exact(&addr->a, del_addr)) {
/* Found the exact match. */
- list_del(pos);
- kfree(addr);
- SCTP_DBG_OBJCNT_DEC(addr);
-
- return 0;
+ addr->valid = 0;
+ list_del_rcu(&addr->list);
+ break;
}
}
+ /* Call the rcu callback provided in the args. This function is
+ * called by both BH packet processing and user side socket option
+ * processing, but it works on different lists in those 2 contexts.
+ * Each context provides it's own callback, whether call_rcu_bh()
+ * or call_rcu(), to make sure that we wait for an appropriate time.
+ */
+ if (addr && !addr->valid) {
+ rcu_call(&addr->rcu, sctp_local_addr_free);
+ SCTP_DBG_OBJCNT_DEC(addr);
+ }
+
return -EINVAL;
}
@@ -300,15 +318,20 @@ int sctp_bind_addr_match(struct sctp_bind_addr *bp,
struct sctp_sock *opt)
{
struct sctp_sockaddr_entry *laddr;
- struct list_head *pos;
-
- list_for_each(pos, &bp->address_list) {
- laddr = list_entry(pos, struct sctp_sockaddr_entry, list);
- if (opt->pf->cmp_addr(&laddr->a, addr, opt))
- return 1;
+ int match = 0;
+
+ rcu_read_lock();
+ list_for_each_entry_rcu(laddr, &bp->address_list, list) {
+ if (!laddr->valid)
+ continue;
+ if (opt->pf->cmp_addr(&laddr->a, addr, opt)) {
+ match = 1;
+ break;
+ }
}
+ rcu_read_unlock();
- return 0;
+ return match;
}
/* Find the first address in the bind address list that is not present in
@@ -323,18 +346,19 @@ union sctp_addr *sctp_find_unmatch_addr(struct sctp_bind_addr *bp,
union sctp_addr *addr;
void *addr_buf;
struct sctp_af *af;
- struct list_head *pos;
int i;
- list_for_each(pos, &bp->address_list) {
- laddr = list_entry(pos, struct sctp_sockaddr_entry, list);
-
+ /* This is only called sctp_send_asconf_del_ip() and we hold
+ * the socket lock in that code patch, so that address list
+ * can't change.
+ */
+ list_for_each_entry(laddr, &bp->address_list, list) {
addr_buf = (union sctp_addr *)addrs;
for (i = 0; i < addrcnt; i++) {
addr = (union sctp_addr *)addr_buf;
af = sctp_get_af_specific(addr->v4.sin_family);
if (!af)
- return NULL;
+ break;
if (opt->pf->cmp_addr(&laddr->a, addr, opt))
break;
diff --git a/net/sctp/endpointola.c b/net/sctp/endpointola.c
index 1404a9e2e78..8f485a0d14b 100644
--- a/net/sctp/endpointola.c
+++ b/net/sctp/endpointola.c
@@ -92,7 +92,6 @@ static struct sctp_endpoint *sctp_endpoint_init(struct sctp_endpoint *ep,
/* Initialize the bind addr area */
sctp_bind_addr_init(&ep->base.bind_addr, 0);
- rwlock_init(&ep->base.addr_lock);
/* Remember who we are attached to. */
ep->base.sk = sk;
@@ -225,21 +224,14 @@ void sctp_endpoint_put(struct sctp_endpoint *ep)
struct sctp_endpoint *sctp_endpoint_is_match(struct sctp_endpoint *ep,
const union sctp_addr *laddr)
{
- struct sctp_endpoint *retval;
+ struct sctp_endpoint *retval = NULL;
- sctp_read_lock(&ep->base.addr_lock);
if (htons(ep->base.bind_addr.port) == laddr->v4.sin_port) {
if (sctp_bind_addr_match(&ep->base.bind_addr, laddr,
- sctp_sk(ep->base.sk))) {
+ sctp_sk(ep->base.sk)))
retval = ep;
- goto out;
- }
}
- retval = NULL;
-
-out:
- sctp_read_unlock(&ep->base.addr_lock);
return retval;
}
@@ -261,9 +253,7 @@ static struct sctp_association *__sctp_endpoint_lookup_assoc(
list_for_each(pos, &ep->asocs) {
asoc = list_entry(pos, struct sctp_association, asocs);
if (rport == asoc->peer.port) {
- sctp_read_lock(&asoc->base.addr_lock);
*transport = sctp_assoc_lookup_paddr(asoc, paddr);
- sctp_read_unlock(&asoc->base.addr_lock);
if (*transport)
return asoc;
@@ -295,20 +285,17 @@ struct sctp_association *sctp_endpoint_lookup_assoc(
int sctp_endpoint_is_peeled_off(struct sctp_endpoint *ep,
const union sctp_addr *paddr)
{
- struct list_head *pos;
struct sctp_sockaddr_entry *addr;
struct sctp_bind_addr *bp;
- sctp_read_lock(&ep->base.addr_lock);
bp = &ep->base.bind_addr;
- list_for_each(pos, &bp->address_list) {
- addr = list_entry(pos, struct sctp_sockaddr_entry, list);
- if (sctp_has_association(&addr->a, paddr)) {
- sctp_read_unlock(&ep->base.addr_lock);
+ /* This function is called with the socket lock held,
+ * so the address_list can not change.
+ */
+ list_for_each_entry(addr, &bp->address_list, list) {
+ if (sctp_has_association(&addr->a, paddr))
return 1;
- }
}
- sctp_read_unlock(&ep->base.addr_lock);
return 0;
}
diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c
index f8aa23dda1c..670fd2740b8 100644
--- a/net/sctp/ipv6.c
+++ b/net/sctp/ipv6.c
@@ -77,13 +77,18 @@
#include <asm/uaccess.h>
-/* Event handler for inet6 address addition/deletion events. */
+/* Event handler for inet6 address addition/deletion events.
+ * The sctp_local_addr_list needs to be protocted by a spin lock since
+ * multiple notifiers (say IPv4 and IPv6) may be running at the same
+ * time and thus corrupt the list.
+ * The reader side is protected with RCU.
+ */
static int sctp_inet6addr_event(struct notifier_block *this, unsigned long ev,
void *ptr)
{
struct inet6_ifaddr *ifa = (struct inet6_ifaddr *)ptr;
- struct sctp_sockaddr_entry *addr;
- struct list_head *pos, *temp;
+ struct sctp_sockaddr_entry *addr = NULL;
+ struct sctp_sockaddr_entry *temp;
switch (ev) {
case NETDEV_UP:
@@ -94,19 +99,26 @@ static int sctp_inet6addr_event(struct notifier_block *this, unsigned long ev,
memcpy(&addr->a.v6.sin6_addr, &ifa->addr,
sizeof(struct in6_addr));
addr->a.v6.sin6_scope_id = ifa->idev->dev->ifindex;
- list_add_tail(&addr->list, &sctp_local_addr_list);
+ addr->valid = 1;
+ spin_lock_bh(&sctp_local_addr_lock);
+ list_add_tail_rcu(&addr->list, &sctp_local_addr_list);
+ spin_unlock_bh(&sctp_local_addr_lock);
}
break;
case NETDEV_DOWN:
- list_for_each_safe(pos, temp, &sctp_local_addr_list) {
- addr = list_entry(pos, struct sctp_sockaddr_entry, list);
- if (ipv6_addr_equal(&addr->a.v6.sin6_addr, &ifa->addr)) {
- list_del(pos);
- kfree(addr);
+ spin_lock_bh(&sctp_local_addr_lock);
+ list_for_each_entry_safe(addr, temp,
+ &sctp_local_addr_list, list) {
+ if (ipv6_addr_equal(&addr->a.v6.sin6_addr,
+ &ifa->addr)) {
+ addr->valid = 0;
+ list_del_rcu(&addr->list);
break;
}
}
-
+ spin_unlock_bh(&sctp_local_addr_lock);
+ if (addr && !addr->valid)
+ call_rcu(&addr->rcu, sctp_local_addr_free);
break;
}
@@ -290,9 +302,7 @@ static void sctp_v6_get_saddr(struct sctp_association *asoc,
union sctp_addr *saddr)
{
struct sctp_bind_addr *bp;
- rwlock_t *addr_lock;
struct sctp_sockaddr_entry *laddr;
- struct list_head *pos;
sctp_scope_t scope;
union sctp_addr *baddr = NULL;
__u8 matchlen = 0;
@@ -312,14 +322,14 @@ static void sctp_v6_get_saddr(struct sctp_association *asoc,
scope = sctp_scope(daddr);
bp = &asoc->base.bind_addr;
- addr_lock = &asoc->base.addr_lock;
/* Go through the bind address list and find the best source address
* that matches the scope of the destination address.
*/
- sctp_read_lock(addr_lock);
- list_for_each(pos, &bp->address_list) {
- laddr = list_entry(pos, struct sctp_sockaddr_entry, list);
+ rcu_read_lock();
+ list_for_each_entry_rcu(laddr, &bp->address_list, list) {
+ if (!laddr->valid)
+ continue;
if ((laddr->use_as_src) &&
(laddr->a.sa.sa_family == AF_INET6) &&
(scope <= sctp_scope(&laddr->a))) {
@@ -341,7 +351,7 @@ static void sctp_v6_get_saddr(struct sctp_association *asoc,
__FUNCTION__, asoc, NIP6(daddr->v6.sin6_addr));
}
- sctp_read_unlock(addr_lock);
+ rcu_read_unlock();
}
/* Make a copy of all potential local addresses. */
@@ -367,7 +377,9 @@ static void sctp_v6_copy_addrlist(struct list_head *addrlist,
addr->a.v6.sin6_port = 0;
addr->a.v6.sin6_addr = ifp->addr;
addr->a.v6.sin6_scope_id = dev->ifindex;
+ addr->valid = 1;
INIT_LIST_HEAD(&addr->list);
+ INIT_RCU_HEAD(&addr->rcu);
list_add_tail(&addr->list, addrlist);
}
}
diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c
index e98579b788b..3d036cdfae4 100644
--- a/net/sctp/protocol.c
+++ b/net/sctp/protocol.c
@@ -153,6 +153,9 @@ static void sctp_v4_copy_addrlist(struct list_head *addrlist,
addr->a.v4.sin_family = AF_INET;
addr->a.v4.sin_port = 0;
addr->a.v4.sin_addr.s_addr = ifa->ifa_local;
+ addr->valid = 1;
+ INIT_LIST_HEAD(&addr->list);
+ INIT_RCU_HEAD(&addr->rcu);
list_add_tail(&addr->list, addrlist);
}
}
@@ -192,16 +195,24 @@ static void sctp_free_local_addr_list(void)
}
}
+void sctp_local_addr_free(struct rcu_head *head)
+{
+ struct sctp_sockaddr_entry *e = container_of(head,
+ struct sctp_sockaddr_entry, rcu);
+ kfree(e);
+}
+
/* Copy the local addresses which are valid for 'scope' into 'bp'. */
int sctp_copy_local_addr_list(struct sctp_bind_addr *bp, sctp_scope_t scope,
gfp_t gfp, int copy_flags)
{
struct sctp_sockaddr_entry *addr;
int error = 0;
- struct list_head *pos, *temp;
- list_for_each_safe(pos, temp, &sctp_local_addr_list) {
- addr = list_entry(pos, struct sctp_sockaddr_entry, list);
+ rcu_read_lock();
+ list_for_each_entry_rcu(addr, &sctp_local_addr_list, list) {
+ if (!addr->valid)
+ continue;
if (sctp_in_scope(&addr->a, scope)) {
/* Now that the address is in scope, check to see if
* the address type is really supported by the local
@@ -213,7 +224,7 @@ int sctp_copy_local_addr_list(struct sctp_bind_addr *bp, sctp_scope_t scope,
(copy_flags & SCTP_ADDR6_ALLOWED) &&
(copy_flags & SCTP_ADDR6_PEERSUPP)))) {
error = sctp_add_bind_addr(bp, &addr->a, 1,
- GFP_ATOMIC);
+ GFP_ATOMIC);
if (error)
goto end_copy;
}
@@ -221,6 +232,7 @@ int sctp_copy_local_addr_list(struct sctp_bind_addr *bp, sctp_scope_t scope,
}
end_copy:
+ rcu_read_unlock();
return error;
}
@@ -416,9 +428,7 @@ static struct dst_entry *sctp_v4_get_dst(struct sctp_association *asoc,
struct rtable *rt;
struct flowi fl;
struct sctp_bind_addr *bp;
- rwlock_t *addr_lock;
struct sctp_sockaddr_entry *laddr;
- struct list_head *pos;
struct dst_entry *dst = NULL;
union sctp_addr dst_saddr;
@@ -447,23 +457,20 @@ static struct dst_entry *sctp_v4_get_dst(struct sctp_association *asoc,
goto out;
bp = &asoc->base.bind_addr;
- addr_lock = &asoc->base.addr_lock;
if (dst) {
/* Walk through the bind address list and look for a bind
* address that matches the source address of the returned dst.
*/
- sctp_read_lock(addr_lock);
- list_for_each(pos, &bp->address_list) {
- laddr = list_entry(pos, struct sctp_sockaddr_entry,
- list);
- if (!laddr->use_as_src)
+ rcu_read_lock();
+ list_for_each_entry_rcu(laddr, &bp->address_list, list) {
+ if (!laddr->valid || !laddr->use_as_src)
continue;
sctp_v4_dst_saddr(&dst_saddr, dst, htons(bp->port));
if (sctp_v4_cmp_addr(&dst_saddr, &laddr->a))
goto out_unlock;
}
- sctp_read_unlock(addr_lock);
+ rcu_read_unlock();
/* None of the bound addresses match the source address of the
* dst. So release it.
@@ -475,10 +482,10 @@ static struct dst_entry *sctp_v4_get_dst(struct sctp_association *asoc,
/* Walk through the bind address list and try to get a dst that
* matches a bind address as the source address.
*/
- sctp_read_lock(addr_lock);
- list_for_each(pos, &bp->address_list) {
- laddr = list_entry(pos, struct sctp_sockaddr_entry, list);
-
+ rcu_read_lock();
+ list_for_each_entry_rcu(laddr, &bp->address_list, list) {
+ if (!laddr->valid)
+ continue;
if ((laddr->use_as_src) &&
(AF_INET == laddr->a.sa.sa_family)) {
fl.fl4_src = laddr->a.v4.sin_addr.s_addr;
@@ -490,7 +497,7 @@ static struct dst_entry *sctp_v4_get_dst(struct sctp_association *asoc,
}
out_unlock:
- sctp_read_unlock(addr_lock);
+ rcu_read_unlock();
out:
if (dst)
SCTP_DEBUG_PRINTK("rt_dst:%u.%u.%u.%u, rt_src:%u.%u.%u.%u\n",
@@ -600,13 +607,18 @@ static void sctp_v4_seq_dump_addr(struct seq_file *seq, union sctp_addr *addr)
seq_printf(seq, "%d.%d.%d.%d ", NIPQUAD(addr->v4.sin_addr));
}
-/* Event handler for inet address addition/deletion events. */
+/* Event handler for inet address addition/deletion events.
+ * The sctp_local_addr_list needs to be protocted by a spin lock since
+ * multiple notifiers (say IPv4 and IPv6) may be running at the same
+ * time and thus corrupt the list.
+ * The reader side is protected with RCU.
+ */
static int sctp_inetaddr_event(struct notifier_block *this, unsigned long ev,
void *ptr)
{
struct in_ifaddr *ifa = (struct in_ifaddr *)ptr;
- struct sctp_sockaddr_entry *addr;
- struct list_head *pos, *temp;
+ struct sctp_sockaddr_entry *addr = NULL;
+ struct sctp_sockaddr_entry *temp;
switch (ev) {
case NETDEV_UP:
@@ -615,19 +627,25 @@ static int sctp_inetaddr_event(struct notifier_block *this, unsigned long ev,
addr->a.v4.sin_family = AF_INET;
addr->a.v4.sin_port = 0;
addr->a.v4.sin_addr.s_addr = ifa->ifa_local;
- list_add_tail(&addr->list, &sctp_local_addr_list);
+ addr->valid = 1;
+ spin_lock_bh(&sctp_local_addr_lock);
+ list_add_tail_rcu(&addr->list, &sctp_local_addr_list);
+ spin_unlock_bh(&sctp_local_addr_lock);
}
break;
case NETDEV_DOWN:
- list_for_each_safe(pos, temp, &sctp_local_addr_list) {
- addr = list_entry(pos, struct sctp_sockaddr_entry, list);
+ spin_lock_bh(&sctp_local_addr_lock);
+ list_for_each_entry_safe(addr, temp,
+ &sctp_local_addr_list, list) {
if (addr->a.v4.sin_addr.s_addr == ifa->ifa_local) {
- list_del(pos);
- kfree(addr);
+ addr->valid = 0;
+ list_del_rcu(&addr->list);
break;
}
}
-
+ spin_unlock_bh(&sctp_local_addr_lock);
+ if (addr && !addr->valid)
+ call_rcu(&addr->rcu, sctp_local_addr_free);
break;
}
@@ -1160,6 +1178,7 @@ SCTP_STATIC __init int sctp_init(void)
/* Initialize the local address list. */
INIT_LIST_HEAD(&sctp_local_addr_list);
+ spin_lock_init(&sctp_local_addr_lock);
sctp_get_local_addr_list();
/* Register notifier for inet address additions/deletions. */
@@ -1227,6 +1246,9 @@ SCTP_STATIC __exit void sctp_exit(void)
sctp_v6_del_protocol();
inet_del_protocol(&sctp_protocol, IPPROTO_SCTP);
+ /* Unregister notifier for inet address additions/deletions. */
+ unregister_inetaddr_notifier(&sctp_inetaddr_notifier);
+
/* Free the local address list. */
sctp_free_local_addr_list();
@@ -1240,9 +1262,6 @@ SCTP_STATIC __exit void sctp_exit(void)
inet_unregister_protosw(&sctp_stream_protosw);
inet_unregister_protosw(&sctp_seqpacket_protosw);
- /* Unregister notifier for inet address additions/deletions. */
- unregister_inetaddr_notifier(&sctp_inetaddr_notifier);
-
sctp_sysctl_unregister();
list_del(&sctp_ipv4_specific.list);
diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c
index 79856c92452..2e34220d94c 100644
--- a/net/sctp/sm_make_chunk.c
+++ b/net/sctp/sm_make_chunk.c
@@ -1531,7 +1531,7 @@ no_hmac:
/* Also, add the destination address. */
if (list_empty(&retval->base.bind_addr.address_list)) {
sctp_add_bind_addr(&retval->base.bind_addr, &chunk->dest, 1,
- GFP_ATOMIC);
+ GFP_ATOMIC);
}
retval->next_tsn = retval->c.initial_tsn;
@@ -2613,22 +2613,16 @@ static int sctp_asconf_param_success(struct sctp_association *asoc,
switch (asconf_param->param_hdr.type) {
case SCTP_PARAM_ADD_IP:
- sctp_local_bh_disable();
- sctp_write_lock(&asoc->base.addr_lock);
- list_for_each(pos, &bp->address_list) {
- saddr = list_entry(pos, struct sctp_sockaddr_entry, list);
+ /* This is always done in BH context with a socket lock
+ * held, so the list can not change.
+ */
+ list_for_each_entry(saddr, &bp->address_list, list) {
if (sctp_cmp_addr_exact(&saddr->a, &addr))
saddr->use_as_src = 1;
}
- sctp_write_unlock(&asoc->base.addr_lock);
- sctp_local_bh_enable();
break;
case SCTP_PARAM_DEL_IP:
- sctp_local_bh_disable();
- sctp_write_lock(&asoc->base.addr_lock);
- retval = sctp_del_bind_addr(bp, &addr);
- sctp_write_unlock(&asoc->base.addr_lock);
- sctp_local_bh_enable();
+ retval = sctp_del_bind_addr(bp, &addr, call_rcu_bh);
list_for_each(pos, &asoc->peer.transport_addr_list) {
transport = list_entry(pos, struct sctp_transport,
transports);
diff --git a/net/sctp/socket.c b/net/sctp/socket.c
index 33354602ae8..772fbfb4bfd 100644
--- a/net/sctp/socket.c
+++ b/net/sctp/socket.c
@@ -367,14 +367,10 @@ SCTP_STATIC int sctp_do_bind(struct sock *sk, union sctp_addr *addr, int len)
if (!bp->port)
bp->port = inet_sk(sk)->num;
- /* Add the address to the bind address list. */
- sctp_local_bh_disable();
- sctp_write_lock(&ep->base.addr_lock);
-
- /* Use GFP_ATOMIC since BHs are disabled. */
+ /* Add the address to the bind address list.
+ * Use GFP_ATOMIC since BHs will be disabled.
+ */
ret = sctp_add_bind_addr(bp, addr, 1, GFP_ATOMIC);
- sctp_write_unlock(&ep->base.addr_lock);
- sctp_local_bh_enable();
/* Copy back into socket for getsockname() use. */
if (!ret) {
@@ -544,15 +540,12 @@ static int sctp_send_asconf_add_ip(struct sock *sk,
if (i < addrcnt)
continue;
- /* Use the first address in bind addr list of association as
- * Address Parameter of ASCONF CHUNK.
+ /* Use the first valid address in bind addr list of
+ * association as Address Parameter of ASCONF CHUNK.
*/
- sctp_read_lock(&asoc->base.addr_lock);
bp = &asoc->base.bind_addr;
p = bp->address_list.next;
laddr = list_entry(p, struct sctp_sockaddr_entry, list);
- sctp_read_unlock(&asoc->base.addr_lock);
-
chunk = sctp_make_asconf_update_ip(asoc, &laddr->a, addrs,
addrcnt, SCTP_PARAM_ADD_IP);
if (!chunk) {
@@ -567,8 +560,6 @@ static int sctp_send_asconf_add_ip(struct sock *sk,
/* Add the new addresses to the bind address list with
* use_as_src set to 0.
*/
- sctp_local_bh_disable();
- sctp_write_lock(&asoc->base.addr_lock);
addr_buf = addrs;
for (i = 0; i < addrcnt; i++) {
addr = (union sctp_addr *)addr_buf;
@@ -578,8 +569,6 @@ static int sctp_send_asconf_add_ip(struct sock *sk,
GFP_ATOMIC);
addr_buf += af->sockaddr_len;
}
- sctp_write_unlock(&asoc->base.addr_lock);
- sctp_local_bh_enable();
}
out:
@@ -651,13 +640,7 @@ static int sctp_bindx_rem(struct sock *sk, struct sockaddr *addrs, int addrcnt)
* socket routing and failover schemes. Refer to comments in
* sctp_do_bind(). -daisy
*/
- sctp_local_bh_disable();
- sctp_write_lock(&ep->base.addr_lock);
-
- retval = sctp_del_bind_addr(bp, sa_addr);
-
- sctp_write_unlock(&ep->base.addr_lock);
- sctp_local_bh_enable();
+ retval = sctp_del_bind_addr(bp, sa_addr, call_rcu);
addr_buf += af->sockaddr_len;
err_bindx_rem:
@@ -748,14 +731,16 @@ static int sctp_send_asconf_del_ip(struct sock *sk,
* make sure that we do not delete all the addresses in the
* association.
*/
- sctp_read_lock(&asoc->base.addr_lock);
bp = &asoc->base.bind_addr;
laddr = sctp_find_unmatch_addr(bp, (union sctp_addr *)addrs,
addrcnt, sp);
- sctp_read_unlock(&asoc->base.addr_lock);
if (!laddr)
continue;
+ /* We do not need RCU protection throughout this loop
+ * because this is done under a socket lock from the
+ * setsockopt call.
+ */
chunk = sctp_make_asconf_update_ip(asoc, laddr, addrs, addrcnt,
SCTP_PARAM_DEL_IP);
if (!chunk) {
@@ -766,23 +751,16 @@ static int sctp_send_asconf_del_ip(struct sock *sk,
/* Reset use_as_src flag for the addresses in the bind address
* list that are to be deleted.
*/
- sctp_local_bh_disable();
- sctp_write_lock(&asoc->base.addr_lock);
addr_buf = addrs;
for (i = 0; i < addrcnt; i++) {
laddr = (union sctp_addr *)addr_buf;
af = sctp_get_af_specific(laddr->v4.sin_family);
- list_for_each(pos1, &bp->address_list) {
- saddr = list_entry(pos1,
- struct sctp_sockaddr_entry,
- list);
+ list_for_each_entry(saddr, &bp->address_list, list) {
if (sctp_cmp_addr_exact(&saddr->a, laddr))
saddr->use_as_src = 0;
}
addr_buf += af->sockaddr_len;
}
- sctp_write_unlock(&asoc->base.addr_lock);
- sctp_local_bh_enable();
/* Update the route and saddr entries for all the transports
* as some of the addresses in the bind address list are
@@ -4059,9 +4037,7 @@ static int sctp_getsockopt_local_addrs_num_old(struct sock *sk, int len,
sctp_assoc_t id;
struct sctp_bind_addr *bp;
struct sctp_association *asoc;
- struct list_head *pos, *temp;
struct sctp_sockaddr_entry *addr;
- rwlock_t *addr_lock;
int cnt = 0;
if (len < sizeof(sctp_assoc_t))
@@ -4078,17 +4054,13 @@ static int sctp_getsockopt_local_addrs_num_old(struct sock *sk, int len,
*/
if (0 == id) {
bp = &sctp_sk(sk)->ep->base.bind_addr;
- addr_lock = &sctp_sk(sk)->ep->base.addr_lock;
} else {
asoc = sctp_id2assoc(sk, id);
if (!asoc)
return -EINVAL;
bp = &asoc->base.bind_addr;
- addr_lock = &asoc->base.addr_lock;
}
- sctp_read_lock(addr_lock);
-
/* If the endpoint is bound to 0.0.0.0 or ::0, count the valid
* addresses from the global local address list.
*/
@@ -4096,27 +4068,33 @@ static int sctp_getsockopt_local_addrs_num_old(struct sock *sk, int len,
addr = list_entry(bp->address_list.next,
struct sctp_sockaddr_entry, list);
if (sctp_is_any(&addr->a)) {
- list_for_each_safe(pos, temp, &sctp_local_addr_list) {
- addr = list_entry(pos,
- struct sctp_sockaddr_entry,
- list);
+ rcu_read_lock();
+ list_for_each_entry_rcu(addr,
+ &sctp_local_addr_list, list) {
+ if (!addr->valid)
+ continue;
+
if ((PF_INET == sk->sk_family) &&
(AF_INET6 == addr->a.sa.sa_family))
continue;
+
cnt++;
}
+ rcu_read_unlock();
} else {
cnt = 1;
}
goto done;
}
- list_for_each(pos, &bp->address_list) {
+ /* Protection on the bound address list is not needed,
+ * since in the socket option context we hold the socket lock,
+ * so there is no way that the bound address list can change.
+ */
+ list_for_each_entry(addr, &bp->address_list, list) {
cnt ++;
}
-
done:
- sctp_read_unlock(addr_lock);
return cnt;
}
@@ -4127,14 +4105,16 @@ static int sctp_copy_laddrs_old(struct sock *sk, __u16 port,
int max_addrs, void *to,
int *bytes_copied)
{
- struct list_head *pos, *next;
struct sctp_sockaddr_entry *addr;
union sctp_addr temp;
int cnt = 0;
int addrlen;
- list_for_each_safe(pos, next, &sctp_local_addr_list) {
- addr = list_entry(pos, struct sctp_sockaddr_entry, list);
+ rcu_read_lock();
+ list_for_each_entry_rcu(addr, &sctp_local_addr_list, list) {
+ if (!addr->valid)
+ continue;
+
if ((PF_INET == sk->sk_family) &&
(AF_INET6 == addr->a.sa.sa_family))
continue;
@@ -4149,6 +4129,7 @@ static int sctp_copy_laddrs_old(struct sock *sk, __u16 port,
cnt ++;
if (cnt >= max_addrs) break;
}
+ rcu_read_unlock();
return cnt;
}
@@ -4156,14 +4137,16 @@ static int sctp_copy_laddrs_old(struct sock *sk, __u16 port,
static int sctp_copy_laddrs(struct sock *sk, __u16 port, void *to,
size_t space_left, int *bytes_copied)
{
- struct list_head *pos, *next;
struct sctp_sockaddr_entry *addr;
union sctp_addr temp;
int cnt = 0;
int addrlen;
- list_for_each_safe(pos, next, &sctp_local_addr_list) {
- addr = list_entry(pos, struct sctp_sockaddr_entry, list);
+ rcu_read_lock();
+ list_for_each_entry_rcu(addr, &sctp_local_addr_list, list) {
+ if (!addr->valid)
+ continue;
+
if ((PF_INET == sk->sk_family) &&
(AF_INET6 == addr->a.sa.sa_family))
continue;
@@ -4171,8 +4154,10 @@ static int sctp_copy_laddrs(struct sock *sk, __u16 port, void *to,
sctp_get_pf_specific(sk->sk_family)->addr_v4map(sctp_sk(sk),
&temp);
addrlen = sctp_get_af_specific(temp.sa.sa_family)->sockaddr_len;
- if (space_left < addrlen)
- return -ENOMEM;
+ if (space_left < addrlen) {
+ cnt = -ENOMEM;
+ break;
+ }
memcpy(to, &temp, addrlen);
to += addrlen;
@@ -4180,6 +4165,7 @@ static int sctp_copy_laddrs(struct sock *sk, __u16 port, void *to,
space_left -= addrlen;
*bytes_copied += addrlen;
}
+ rcu_read_unlock();
return cnt;
}
@@ -4192,7 +4178,6 @@ static int sctp_getsockopt_local_addrs_old(struct sock *sk, int len,
{
struct sctp_bind_addr *bp;
struct sctp_association *asoc;
- struct list_head *pos;
int cnt = 0;
struct sctp_getaddrs_old getaddrs;
struct sctp_sockaddr_entry *addr;
@@ -4200,7 +4185,6 @@ static int sctp_getsockopt_local_addrs_old(struct sock *sk, int len,
union sctp_addr temp;
struct sctp_sock *sp = sctp_sk(sk);
int addrlen;
- rwlock_t *addr_lock;
int err = 0;
void *addrs;
void *buf;
@@ -4222,13 +4206,11 @@ static int sctp_getsockopt_local_addrs_old(struct sock *sk, int len,
*/
if (0 == getaddrs.assoc_id) {
bp = &sctp_sk(sk)->ep->base.bind_addr;
- addr_lock = &sctp_sk(sk)->ep->base.addr_lock;
} else {
asoc = sctp_id2assoc(sk, getaddrs.assoc_id);
if (!asoc)
return -EINVAL;
bp = &asoc->base.bind_addr;
- addr_lock = &asoc->base.addr_lock;
}
to = getaddrs.addrs;
@@ -4242,8 +4224,6 @@ static int sctp_getsockopt_local_addrs_old(struct sock *sk, int len,
if (!addrs)
return -ENOMEM;
- sctp_read_lock(addr_lock);
-
/* If the endpoint is bound to 0.0.0.0 or ::0, get the valid
* addresses from the global local address list.
*/
@@ -4259,8 +4239,11 @@ static int sctp_getsockopt_local_addrs_old(struct sock *sk, int len,
}
buf = addrs;
- list_for_each(pos, &bp->address_list) {
- addr = list_entry(pos, struct sctp_sockaddr_entry, list);
+ /* Protection on the bound address list is not needed since
+ * in the socket option context we hold a socket lock and
+ * thus the bound address list can't change.
+ */
+ list_for_each_entry(addr, &bp->address_list, list) {
memcpy(&temp, &addr->a, sizeof(temp));
sctp_get_pf_specific(sk->sk_family)->addr_v4map(sp, &temp);
addrlen = sctp_get_af_specific(temp.sa.sa_family)->sockaddr_len;
@@ -4272,8 +4255,6 @@ static int sctp_getsockopt_local_addrs_old(struct sock *sk, int len,
}
copy_getaddrs:
- sctp_read_unlock(addr_lock);
-
/* copy the entire address list into the user provided space */
if (copy_to_user(to, addrs, bytes_copied)) {
err = -EFAULT;
@@ -4295,7 +4276,6 @@ static int sctp_getsockopt_local_addrs(struct sock *sk, int len,
{
struct sctp_bind_addr *bp;
struct sctp_association *asoc;
- struct list_head *pos;
int cnt = 0;
struct sctp_getaddrs getaddrs;
struct sctp_sockaddr_entry *addr;
@@ -4303,7 +4283,6 @@ static int sctp_getsockopt_local_addrs(struct sock *sk, int len,
union sctp_addr temp;
struct sctp_sock *sp = sctp_sk(sk);
int addrlen;
- rwlock_t *addr_lock;
int err = 0;
size_t space_left;
int bytes_copied = 0;
@@ -4324,13 +4303,11 @@ static int sctp_getsockopt_local_addrs(struct sock *sk, int len,
*/
if (0 == getaddrs.assoc_id) {
bp = &sctp_sk(sk)->ep->base.bind_addr;
- addr_lock = &sctp_sk(sk)->ep->base.addr_lock;
} else {
asoc = sctp_id2assoc(sk, getaddrs.assoc_id);
if (!asoc)
return -EINVAL;
bp = &asoc->base.bind_addr;
- addr_lock = &asoc->base.addr_lock;
}
to = optval + offsetof(struct sctp_getaddrs,addrs);
@@ -4340,8 +4317,6 @@ static int sctp_getsockopt_local_addrs(struct sock *sk, int len,
if (!addrs)
return -ENOMEM;
- sctp_read_lock(addr_lock);
-
/* If the endpoint is bound to 0.0.0.0 or ::0, get the valid
* addresses from the global local address list.
*/
@@ -4353,21 +4328,24 @@ static int sctp_getsockopt_local_addrs(struct sock *sk, int len,
space_left, &bytes_copied);
if (cnt < 0) {
err = cnt;
- goto error_lock;
+ goto out;
}
goto copy_getaddrs;
}
}
buf = addrs;
- list_for_each(pos, &bp->address_list) {
- addr = list_entry(pos, struct sctp_sockaddr_entry, list);
+ /* Protection on the bound address list is not needed since
+ * in the socket option context we hold a socket lock and
+ * thus the bound address list can't change.
+ */
+ list_for_each_entry(addr, &bp->address_list, list) {
memcpy(&temp, &addr->a, sizeof(temp));
sctp_get_pf_specific(sk->sk_family)->addr_v4map(sp, &temp);
addrlen = sctp_get_af_specific(temp.sa.sa_family)->sockaddr_len;
if (space_left < addrlen) {
err = -ENOMEM; /*fixme: right error?*/
- goto error_lock;
+ goto out;
}
memcpy(buf, &temp, addrlen);
buf += addrlen;
@@ -4377,8 +4355,6 @@ static int sctp_getsockopt_local_addrs(struct sock *sk, int len,
}
copy_getaddrs:
- sctp_read_unlock(addr_lock);
-
if (copy_to_user(to, addrs, bytes_copied)) {
err = -EFAULT;
goto out;
@@ -4389,12 +4365,6 @@ copy_getaddrs:
}
if (put_user(bytes_copied, optlen))
err = -EFAULT;
-
- goto out;
-
-error_lock:
- sctp_read_unlock(addr_lock);
-
out:
kfree(addrs);
return err;
diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c
index 12ff5da8160..1a899924023 100644
--- a/net/sunrpc/svcsock.c
+++ b/net/sunrpc/svcsock.c
@@ -1592,7 +1592,7 @@ svc_age_temp_sockets(unsigned long closure)
if (!test_and_set_bit(SK_OLD, &svsk->sk_flags))
continue;
- if (atomic_read(&svsk->sk_inuse) || test_bit(SK_BUSY, &svsk->sk_flags))
+ if (atomic_read(&svsk->sk_inuse) > 1 || test_bit(SK_BUSY, &svsk->sk_flags))
continue;
atomic_inc(&svsk->sk_inuse);
list_move(le, &to_be_aged);